Tính đa hình C#
Tính đa hình là một trong các đặc tính của lập trình hướng đối tượng, trong phần quá tải phương thức - nó đã thể hiện tính đa hình. Tính đa hình của nghĩa là có nhiều dạng, tính đa hình sẽ thể hiện rõ khi xây dựng các lớp kế thừa. Một phương thức được gọi, nó sẽ là phương thức cụ thể nào tùy thuộc vào đối tượng lúc nó thực thi.
Phương thức ảo (hàm ảo) C#
Một phương thức ảo trong lớp - là phương thức có thể định nghĩa lại (bị nạp chồng - bị đè) bởi
lớp kế thừa. Muốn một phương thức là ảo, thêm từ khóa virtual
vào khai báo tên hàm.
class Product { protected double price = 0; // Phương thức ảo ProductInfo public virtual void ProductInfo() { Console.WriteLine($"Giá sản phẩm {price}"); } public void TestProduct() { this.ProductInfo(); } }
Vì phương thức ProductInfo
khai báo là loại phương thức virtual
,
nên ở lớp kế thừa nó, có thể định nghĩa lại - kỹ thuật này gọi là nạp chồng (override)
Nạp chồng phương thức
Ở lớp kế thừa, có thể định nghĩa lại phương thức ảo của lớp cơ sở, việc này là thực hiện nạp chồng,
để nạp chồng chỉ việc khai báo lại phương thức thêm vào từ khóa override
class Iphone : Product { public Iphone() { price = 500; } public override void ProductInfo() { Console.WriteLine($"Điện thoại Iphone"); base.ProductInfo(); } }
Khi sử dụng:
Product p1 = new Product(); Product p2 = new Iphone(); p1.TestProduct(); // In ra: Giá sản phẩm 0 p2.TestProduct(); // In ra: Điện thoại Iphone Gọi đến ProductInfo đã định nghĩa lại
Lớp Iphone đã định nghĩa lại phương thức ProductInfo, nên các lời gọi đến ProductInfo là hoàn toàn
khác với định nghĩa ban đầu của nó. Tuy nhiên, nếu muốn thi hành code của hàm mà do lớp cơ sở định nghĩa
thì bạn cần gọi đến nó thông qua ký hiệu base.
class Iphone : Product { public Iphone() { price = 500; } public override void ProductInfo() { Console.WriteLine($"Điện thoại Iphone"); base.ProductInfo(); // gọi lại hàm ở base } }
Product p = new Iphone(); p.TestProduct(); // Điện thoại Iphone // Giá sản phẩm 500
Để nhìn rõ hơn về tính đa hình, viết lại 2 đoạn code như sau:
Product p = new Product(); p.TestProduct();
Product p = new Iphone(); p.TestProduct();
Đều gọi phương thức TestProduct()
của lớp cơ sở, nhưng nó lại thi hành những tác vụ khác nhau.
Lớp trừu tượng / Phương thức trừu tượng
Lớp trừu tượng cũng là một trường hợp thể hiện tính đa hình của lập trình OOP, khi khai báo một lớp có từ khóa
abstract
thì nó là lớp trừu tượng. Đã là lớp trừu tượng thì nó không được dùng để khởi tạo đối tượng
trực tiếp mà nó chỉ làm lớp cơ sở kế thừa bởi lớp khác.
Trong lớp trừu tượng, còn có thể khai báo phương thức trừu tượng với từ khóa abstract
,
phương thức này không có thân (chỉ có tên - tham số), nó yêu cầu lớp kế thừa bắt buộc phải nạp chồng (overrid)
abstract class Product { protected double price = 0; public abstract void ProductInfo(); public void TestProduct() { this.ProductInfo(); } }
Định nghĩa như trên, Product là lớp trừu tượng, nó có một hàm trừu tượng là ProductInfo(), hàm này yêu cầu lớp kế thừa phải overrid nó. Do Product là lớp trừu tượng, nên nó không bao giờ được dùng để tạo đối tượng.
Product p = new Product(); // lỗi vì sử dụng abstract tạo đối tượng
Product chỉ dùng để kế thừa, hàm abstract bắt buộc phải overrid
class Iphone : Product { public Iphone() { price = 500; } public override void ProductInfo() { Console.WriteLine($"Điện thoại Iphone"); } } class Laptop : Product { public Laptop() { price = 1500; } public override void ProductInfo() { Console.WriteLine($"Máy Laptop ... "); } }
Product p1 = new Iphone(); Product p2 = new Laptop(); p1.TestProduct(); // Điện thoại Iphone p2.TestProduct(); // Máy Laptop ...
Giao diện - Interface
Giao diện (interface) nó có ý nghĩa gần giống với lớp abstract. Chỉ có điều khai báo thì dùng
từ khóa interface
thay cho từ khóa class
và điều quan trọng -
tất cả các phương thức đều khai báo không có thân (chỉ có tên - nghĩa là phương thức abstract).. Lớp triển khai giao diện (lớp kế thừa) bắt buộc phải định nghĩa lại (không cần từ khóa
overrid) tất cả các phương thức này, cũng có một
điều khác là lớp kế thừa có thể kế thừa nhiều giao diện.
interface IProduct { public void ShowPrice(); } interface IOrder { public void OrderAction(int numberProduct); } class Product : IProduct, IOrder { double price; public Product(double price) { this.price = price; } public void ShowPrice() { Console.WriteLine($"Price: {price}"); } public void OrderAction(int numberProduct) { Console.WriteLine($"Order: {numberProduct}"); } }
Ở trên, Product đã triển khai hai giao diện (IProduct, IOrder)
Vậy giao diện, giống như những mẫu - mà lớp triển khai bắt buộc phải có các phương thức giống nó.