Các lớp trừu tượng và Giao diện
- 27-11-2023
- Toanngo92
- 0 Comments
Một lớp được định nghĩa bằng từ khóa abstract và chứa ít nhất một phương thức không có nội dung được gọi là lớp trừu tượng. Tuy nhiên, nó có thể chứa các phương thức khác được thực hiện trong lớp. Một giao diện, giống như một lớp trừu tượng, có thể khai báo các phương thức trừu tượng. Không giống như lớp trừu tượng, một giao diện không thể thực hiện bất kỳ phương thức nào. Trong phiên này, bạn sẽ học:
- Định nghĩa và mô tả các lớp trừu tượng
- Giải thích về giao diện
- So sánh lớp trừu tượng và giao diện
Mục lục
Các lớp trừu tượng
Trong C#, bạn có thể thiết kế một lớp được sử dụng đặc biệt làm lớp cơ sở bằng cách khai báo nó là một lớp trừu tượng. Lớp như vậy có thể được gọi là một lớp cơ sở không hoàn chỉnh, vì nó không thể được khởi tạo, nhưng chỉ có thể được triển khai hoặc kế thừa.
Một lớp trừu tượng là một lớp được khai báo bằng từ khóa abstract và có thể chứa một hoặc nhiều trong các thành phần sau: các thành viên dữ liệu bình thường, các phương thức bình thường và các phương thức trừu tượng.
Mục đích
Xem xét lớp cơ sở, Animal, định nghĩa các phương thức như Eat(), Habitat(), và AnimalSound(). Lớp Animal được kế thừa bởi các lớp con khác nhau như Dog, Cat, Lion và Tiger. Các loài chó, mèo, sư tử và hổ không chia sẻ cùng loại thức ăn hoặc môi trường sống và cũng không phát ra âm thanh tương tự. Vì vậy, các phương thức Eat(), Habitat() và AnimalSound() phải khác nhau cho các loài động vật khác nhau ngay cả khi chúng kế thừa cùng một lớp cơ sở. Những khác biệt này có thể được tích hợp bằng cách sử dụng các lớp trừu tượng.
Hình bên dưới hiển thị một ví dụ về lớp trừu tượng và các lớp con.
Định nghĩa
Một lớp trừu tượng có thể triển khai các phương thức giống nhau cho tất cả các lớp con. Ngoài ra, nó có thể khai báo các phương thức khác nhau cho các lớp con mà không triển khai chúng. Các phương thức như vậy được gọi là các phương thức trừu tượng.
Một lớp được định nghĩa bằng từ khóa abstract và chứa ít nhất một phương thức không được triển khai trong chính lớp đó được gọi là lớp trừu tượng. Trong trường hợp không có từ khóa abstract, lớp đó không thể được biên dịch. Vì lớp trừu tượng chứa ít nhất một phương thức không có thân, lớp không thể được khởi tạo bằng từ khóa new.
Hình bên dưới hiển thị nội dung của một lớp trừu tượng.
Dưới đây là cú pháp sử dụng để khai báo một lớp trừu tượng:
public abstract class <ClassName>
{
<access_modifier> abstract <return_type> <MethodName>(argument_list)
}
trong đó,
- abstract: Xác định rằng lớp được khai báo là trừu tượng.
- ClassName: Chỉ ra tên của lớp.
Đoạn mã bên dưới khai báo một lớp trừu tượng Animal.
public abstract class Animal
{
// Phương thức không trừu tượng được triển khai
public void Eat()
{
Console.WriteLine("Every animal eats food in order to survive");
}
// Khai báo phương thức trừu tượng
public abstract void AnimalSound();
public abstract void Habitat();
}
Trong đoạn mã số trên, lớp trừu tượng Animal được tạo ra bằng từ khóa abstract. Lớp Animal triển khai phương thức không trừu tượng Eat(), cũng như khai báo hai phương thức trừu tượng AnimalSound() và Habitat().
Lưu ý: Không bắt buộc lớp trừu tượng chỉ chứa các phương thức trừu tượng. Nó có thể chứa cả các phương thức không trừu tượng. Một lớp trừu tượng không thể được gắn kín (sealed).
Triển khai
Một lớp trừu tượng có thể được triển khai tương tự như cách triển khai một lớp cơ sở bình thường. Lớp con kế thừa từ lớp trừu tượng phải ghi đè và triển khai các phương thức trừu tượng. Ngoài ra, lớp con có thể triển khai các phương thức đã được triển khai trong lớp trừu tượng với cùng tên và các đối số tương tự.
Nếu lớp con không triển khai các phương thức trừu tượng, lớp con đó không thể được khởi tạo vì trình biên dịch C# coi nó như một lớp trừu tượng.
Hình bên dưới hiển thị một ví dụ về việc kế thừa một lớp trừu tượng.
Cú pháp sau được sử dụng để triển khai một lớp trừu tượng:
class <ClassName> : <AbstractClassName>
{
//class members
}
trong đó,
- ClassName: Chỉ ra tên của lớp được triển khai.
- AbstractClassName: Xác định tên của lớp trừu tượng được kế thừa.
Đoạn mã bên dưới khai báo và triển khai một lớp trừu tượng.
using System;
abstract class Animal {
public void Eat() {
Console.WriteLine("Every animal eats food in order to survive");
}
public abstract void AnimalSound();
}
class Lion : Animal {
public override void AnimalSound() {
Console.WriteLine("Lion roars");
}
static void Main(string[] args) {
Lion objLion = new Lion();
objLion.AnimalSound();
objLion.Eat();
}
}
Trong đoạn mã trên, lớp trừu tượng Animal được khai báo và lớp Lion kế thừa từ lớp trừu tượng Animal. Vì lớp Animal khai báo một phương thức trừu tượng có tên là AnimalSound(), nên lớp Lion ghi đè phương thức AnimalSound() bằng từ khóa override và triển khai nó. Phương thức Main trong lớp Lion sau đó gọi các phương thức AnimalSound() và Eat().
Kết quả:
Lion roars
Every animal eats food in order to survive
Triển khai lớp cơ sở trừu tượng bằng IntelliSense
Intellisense cung cấp quyền truy cập vào biến thành viên, hàm và phương thức của một đối tượng hoặc một lớp. Do đó, nó giúp lập trình viên dễ dàng phát triển phần mềm bằng cách giảm lượng nhập liệu cần gõ vào, khiến việc nhập liệu trở nên dễ dàng hơn. IntelliSense có thể được sử dụng để triển khai các lớp trừu tượng được định nghĩa sẵn trong hệ thống.
Các bước triển khai một lớp trừu tượng bằng IntelliSense như sau:
- Di chuyển con trỏ sau khai báo lớp IntellisenseDemo.
- Gõ: TimeZone. Bây giờ khai báo lớp trở thành: class IntellisenseDemo : TimeZone. (Lớp TimeZone là một lớp được định nghĩa sẵn trong hệ thống biểu thị cho múi giờ mà thời gian chuẩn đang được sử dụng.)
- Nhấp vào thẻ thông minh xuất hiện dưới lớp TimeZone.
- Nhấp vào “Implement abstract class System.TimeZone”. IntelliSense cung cấp bốn phương thức ghi đè từ lớp TimeZone được định nghĩa sẵn cho lớp IntellisenseDemo được người dùng định nghĩa.
Đoạn mã bên dưới biểu diễn cách các phương thức của lớp trừu tượng TimeZone được gọi tự động bởi IntelliSense.
using System;
class IntelliSenseDemo : TimeZone
{
public override string DaylightName
{
get { throw new Exception("The method or operation is not implemented.");
}
public override System.Globalization.DaylightTime GetDaylightChanges(int year)
{
throw new Exception("The method or operation is not implemented.");
}
public override TimeSpan GetUtcOffset(DateTime time)
{
throw new Exception("The method or operation is not implemented.");
}
public override string StandardName
{
get { throw new Exception("The method or operation is not implemented.");
}
}
}
Phương thức trừu tượng
Các phương thức trong lớp trừu tượng được khai báo mà không có thân hàm được gọi là các phương thức trừu tượng. Những phương thức này được triển khai trong lớp kế thừa.
Tương tự như một phương thức thông thường, một phương thức trừu tượng được khai báo với một bộ điều chỉnh truy cập, một kiểu trả về và một chữ ký. Tuy nhiên, phương thức trừu tượng không có thân hàm và khai báo phương thức kết thúc bằng dấu chấm phẩy.
Các phương thức trừu tượng cung cấp một chức năng chung cho các lớp kế thừa từ lớp trừu tượng. Các lớp con của lớp trừu tượng có thể ghi đè và triển khai các phương thức trừu tượng.
Hình bên dưới biểu diễn một ví dụ về các phương thức trừu tượng.
Kế thừa Đa hình qua Giao diện
Trong C#, một lớp con không thể kế thừa hai hoặc nhiều lớp cơ sở. Điều này là do C# không hỗ trợ kế thừa đa lớp. Để vượt qua hạn chế này, giao diện đã được giới thiệu. Một lớp trong C# có thể triển khai nhiều giao diện.
Mục đích
Xem xét một lớp Dog cần kế thừa các tính năng của các lớp Canine và Animal. Lớp Dog không thể kế thừa các phương thức từ cả hai lớp này vì C# không hỗ trợ kế thừa đa lớp. Tuy nhiên, nếu Canine và Animal được khai báo là các giao diện, lớp Dog có thể triển khai các phương thức từ cả hai giao diện.
Hình bên dưới biểu diễn một ví dụ về các lớp con trong C#.
Giao diện
Một giao diện chỉ chứa các thành viên trừu tượng. Khác với một lớp trừu tượng, một giao diện không thể triển khai bất kỳ phương thức nào. Tương tự như một lớp trừu tượng, một giao diện không thể được khởi tạo. Một giao diện chỉ có thể được kế thừa bởi các lớp hoặc các giao diện khác.
Một giao diện được khai báo bằng từ khóa interface. Trong C#, mặc định, tất cả các thành viên được khai báo trong một giao diện có chia sẻ bộ điều chỉnh truy cập. Hình bên dưới mô tả một ví dụ về một giao diện.
Cú pháp sau được sử dụng để khai báo một giao diện:
interface <InterfaceName>
{
//interface members
}
trong đó,
- interface: Khai báo một giao diện.
- InterfaceName: Là tên của giao diện.
Đoạn mã bên dưới khai báo một giao diện Animal.
interface <IAnimal>
{
//void AnimalType();
}
Trong đoạn mã trên, giao diện Animal được khai báo và giao diện khai báo một phương thức trừu tượng AnimalType().
Lưu ý: Giao diện không thể chứa các hằng số, trường dữ liệu, hàm tạo, hàm hủy, và các thành viên tĩnh.
Triển khai một giao diện
Một giao diện được triển khai bởi một lớp một cách tương tự như kế thừa từ một lớp. Khi triển khai một giao diện trong một lớp, bạn phải triển khai tất cả các phương thức trừu tượng được khai báo trong giao diện. Nếu không triển khai đầy đủ các phương thức, lớp sẽ không thể được biên dịch. Các phương thức được triển khai trong lớp nên được khai báo với cùng tên và chữ ký như đã được định nghĩa trong giao diện.
Hình bên dưới mô tả việc triển khai một giao diện.
Đoạn mã sau được sử dụng để triển khai một giao diện:
class <ClassName> : <InterfaceName>
{
//Implement the interface methods
//class members
}
trong đó,
- InterfaceName: Chỉ định tên của giao diện
Đoạn mã bên dưới khai báo một giao diện IAnimal và triển khai nó trong lớp Dog.
interface IAnimal {
void Habitat();
}
class Dog : IAnimal {
public void Habitat() {
Console.WriteLine("Can be housed with human beings");
}
static void Main(string[] args) {
Dog objDog = new Dog();
Console.WriteLine(objDog.GetType().Name);
objDog.Habitat();
}
}
Đoạn mã trên tạo ra một giao diện IAnimal khai báo phương thức Habitat(). Lớp Dog triển khai giao diện Animal và phương thức Habitat(). Trong phương thức Main() của lớp Dog, tên của lớp được hiển thị bằng đối tượng, sau đó, phương thức Habitat() được gọi bằng thể hiện của lớp Dog.
Kết quả:
Dog
Can be housed with human beings
Giao diện và kế thừa đa hình
Có thể triển khai nhiều giao diện trong một lớp duy nhất. Triển khai này cung cấp chức năng của việc kế thừa đa hình. Bạn có thể triển khai nhiều giao diện bằng cách đặt dấu phẩy giữa các tên giao diện khi triển khai chúng trong một lớp.
Một lớp triển khai nhiều giao diện phải triển khai tất cả các phương thức trừu tượng được khai báo trong các giao diện. Từ khóa override không được sử dụng khi triển khai các phương thức trừu tượng của một giao diện.
Hình bên dưới mô tả khái niệm về kế thừa đa hình.
Cú pháp dưới đây được sử dụng để triển khai nhiều giao diện:
class <ClassName> : <Interface1>, <Interface2>
{
//Implement the interface method:
}
trong đó,
- Interface1: Chỉ định tên của giao diện đầu tiên.
- Interface2: Chỉ định tên của giao diện thứ hai.
Đoạn mã bên dưới khai báo và triển khai nhiều giao diện.
interface ITerrestrialAnimal {
void Eat();
}
interface IMarineAnimal {
void Swim();
}
class Crocodile: ITerrestrialAnimal, IMarineAnimal {
public void Eat() {
Console.WriteLine ("The Crocodile eats flesh");
}
public void Swim() {
Console.WriteLine ("The Crocodile can swim four times faster than an Olympic swimmer");
}
}
static void Main(string[] args) {
Crocodile objCrocodile = new Crocodile ();
objCrocodile.Eat ();
objCrocodile.Swim();
}
Trong Đoạn mã trên, các giao diện ITerrestrialAnimal và IMarineAnimal được khai báo. Hai giao diện này khai báo phương thức Eat() và Swim().
Kết quả:
The Crocodile eats flesh
The Crocodile can swim four times faster than an Olympic swimmer
Lưu ý: C# cho phép bạn kế thừa một lớp cơ sở và triển khai hơn một giao diện cùng một lúc.
Triển khai giao diện một cách rõ ràng
Một lớp phải triển khai một cách rõ ràng nhiều giao diện nếu các giao diện này có các phương thức có cùng tên. Ngoài ra, nếu một giao diện có tên phương thức giống với tên phương thức được khai báo trong lớp kế thừa, giao diện này cũng phải được triển khai một cách rõ ràng.
Xét các giao diện ITerrestrialAnimal và IMarineAnimal. Giao diện ITerrestrialAnimal khai báo phương thức Eat() và Habitat(). Giao diện IMarineAnimal khai báo phương thức Eat() và Swim(). Lớp Crocodile triển khai hai giao diện này phải triển khai phương thức Eat() từ cả hai giao diện bằng cách chỉ định tên giao diện trước tên phương thức.
Trong khi triển khai một giao diện một cách rõ ràng, bạn không thể đề cập đến các từ khóa như override, new, virtual.
Hình bên dưới hiển thị triển khai rõ ràng của giao diện.
Cú pháp sau được sử dụng để triển khai rõ ràng các giao diện:
class YourClass : Interface1, Interface2
{
// Implementing Interface1's method
<accessmodifier> void Interface1.Method()
{
// Statements for implementing Interface1's method
}
// Implementing Interface2's method
<accessmodifier> void Interface2.Method()
{
// Statements for implementing Interface2's method
}
}
trong đó,
- Interface1: Chỉ định giao diện đầu tiên được triển khai.
- Interface2: Chỉ định giao diện thứ hai được triển khai.
- Method(): Chỉ định cùng tên phương thức được khai báo trong hai giao diện.
Đoạn mã bên dưới trình bày cách sử dụng các giao diện triển khai một cách rõ ràng.
interface ITerrestrialAnimal {
string Eat();
}
interface IMarineAnimal {
string Eat();
}
class Crocodile : ITerrestrialAnimal, IMarineAnimal {
string ITerrestrialAnimal.Eat() {
string terCroc = "Crocodile eats other animals.";
return terCroc;
}
string IMarineAnimal.Eat() {
string marCroc = "Crocodile eats fish and marine animals.";
return marCroc;
}
public string EatTerrestrial() {
ITerrestrialAnimal objTerAnimal = this;
return objTerAnimal.Eat();
}
public string EatMarine() {
IMarineAnimal objMarAnimal = this;
return objMarAnimal.Eat();
}
public static void Main(string[] args) {
Crocodile objCrocodile = new Crocodile();
string terCroc = objCrocodile.EatTerrestrial();
Console.WriteLine(terCroc);
string marCroc = objCrocodile.EatMarine();
Console.WriteLine(marCroc);
}
}
Trong đoạn mã trên lớp Crocodile triển khai một cách rõ ràng phương thức Eat() của hai giao diện, ITerrestrialAnimal và IMarineAnimal. Phương thức Eat() được gọi bằng cách tạo một tham chiếu của hai giao diện và sau đó gọi phương thức.
Kết quả:
Crocodile eats other animals.
Crocodile eats fish and marine animals
Kế thừa Giao diện
Một giao diện có thể kế thừa nhiều giao diện khác nhau nhưng không thể triển khai chúng. Việc triển khai này phải được thực hiện bởi một lớp.
Giả sử có ba giao diện: IAnimal, ICarnivorous và IReptile. Giao diện IAnimal khai báo các phương thức xác định hành vi chung của tất cả động vật. Giao diện ICarnivorous khai báo các phương thức xác định thói quen ăn của động vật ăn thịt. Giao diện IReptile kế thừa các giao diện IAnimal và ICarnivorous. Tuy nhiên, những giao diện này không thể được triển khai bởi giao diện IReptile vì giao diện không thể triển khai các phương thức. Lớp triển khai giao diện IReptile phải triển khai các phương thức được khai báo trong giao diện IReptile cũng như các phương thức được khai báo trong các giao diện Animal và ICarnivorous.
Hình bên dưới trình bày một ví dụ về kế thừa giao diện.
Dưới đây là cú pháp được sử dụng để kế thừa một giao diện trong C#:
interface <InterfaceName> : <Inherited_InterfaceName>
{
// method declaration;
}
trong đó,
- InterfaceName: Chỉ định tên của giao diện kế thừa giao diện khác.
- Inherited_InterfaceName: Chỉ định tên của giao diện kế thừa.
Đoạn mã bên dưới khai báo các giao diện được kế thừa bởi các giao diện khác.
using System;
interface IAnimal {
void Drink();
}
interface ICarnivorous {
void Eat();
}
interface IReptile : IAnimal, ICarnivorous {
void Habitat();
}
class Crocodile : IReptile {
public void Drink() {
Console.WriteLine("Drinks freshwater");
}
public void Habitat() {
Console.WriteLine("Can stay in Water and Land");
}
public void Eat() {
Console.WriteLine("Eats Flesh");
}
public static void Main(string[] args) {
Crocodile objCrocodile = new Crocodile();
Console.WriteLine(objCrocodile.GetType().Name);
objCrocodile.Habitat();
objCrocodile.Eat();
objCrocodile.Drink();
}
}
Trong đoạn mã trên, ba giao diện IAnimal, ICarnivorous và IReptile được khai báo. Ba giao diện này khai báo các phương thức Drink(), Eat() và Habitat() tương ứng. Giao diện IReptile kế thừa các giao diện IAnimal và ICarnivorous. Lớp Crocodile thực hiện giao diện IReptile, phương thức Habitat() đã được khai báo và các phương thức Eat() và Drink() được kế thừa từ các giao diện ICarnivorous và IAnimal.
Kết quả:
Crocodile
Can stay in Water and Land
Eats Flesh
Drinks fresh
Tái triển khai giao diện
Một lớp có thể tái triển khai một giao diện. Việc tái triển khai xảy ra khi phương thức được khai báo trong giao diện được thực hiện trong một lớp bằng từ khóa virtual và phương thức ảo này sau đó được ghi đè trong lớp dẫn xuất.
Đoạn mã bên dưới thể hiện mục đích của việc tái triển khai một giao diện.
using System;
interface IMath {
void Area();
}
class Circle : IMath {
public const float PI = 3.14F;
protected float Radius;
protected double AreaOfCircle;
public virtual void Area() {
AreaOfCircle = (PI * Radius * Radius);
}
}
class Sphere : Circle {
private double _areaOfSphere;
public override void Area() {
base.Area();
_areaOfSphere = (AreaOfCircle * 4);
}
public static void Main(string[] args) {
Sphere objSphere = new Sphere();
objSphere.Radius = 7;
objSphere.Area();
Console.WriteLine("Area of Sphere: {0:F2}", objSphere._areaOfSphere);
}
}
Trong Đoạn mã trên, giao diện IMath khai báo phương thức Area(). Lớp Circle thực hiện giao diện IMath. Lớp Circle khai báo một phương thức ảo Area() để tính diện tích của một hình tròn. Lớp Sphere kế thừa lớp Circle và ghi đè phương thức của lớp cơ sở Area() để tính diện tích của quả cầu. Từ khóa base gọi phương thức của lớp cơ sở Area (), cho phép sử dụng các phương thức của lớp cơ sở trong lớp dẫn xuất.
Hình bên dưới hiển thị kết quả của việc tái triển khai một giao diện.
Toán tử is và as trong giao diện
Toán tử is và as trong C# xác minh xem giao diện cụ thể đã được triển khai hay chưa. Toán tử này được sử dụng để kiểm tra tính tương thích giữa hai loại hoặc lớp. Nó trả về một giá trị boolean dựa trên phép kiểm tra thực hiện. Mặt khác, toán tử as trả về null nếu hai loại hoặc lớp không tương thích với nhau.
Đoạn mã bên dưới thể hiện một giao diện với toán tử is.
using System;
interface ICalculate {
double Area();
}
class Rectangle : ICalculate {
float _length;
float _breadth;
public Rectangle(float valOne, float valTwo) {
_length = valOne;
_breadth = valTwo;
}
public double Area() {
return _length * _breadth;
}
public static void Main(string[] args) {
Rectangle objRectangle = new Rectangle(10.2F, 20.3F);
if (objRectangle is ICalculate) {
Console.WriteLine("Area of rectangle: {0:F2}", objRectangle.Area());
} else {
Console.WriteLine("Interface method not implemented");
}
}
}
Đoạn mã trên định nghĩa một interface Calculate với phương thức Area(). Lớp Rectangle triển khai interface Calculate và bao gồm một hàm tạo có tham số gán các giá trị kích thước của hình chữ nhật. Phương thức Area() tính diện tích của hình chữ nhật. Phương thức main tạo một thể hiện của lớp Rectangle. Toán tử is được sử dụng trong khối if để kiểm tra xem lớp Rectangle có triển khai các phương thức được khai báo trong interface ICalculate hay không.
Hình bên dưới hiển thị kết quả của ví dụ sử dụng toán tử is.
Đoạn mã bên dưới minh họa giao diện với toán tử as.
using System;
interface ISet {
void AcceptDetails(int valOne, string valTwo);
}
interface IGet {
void Display();
}
class Employee : ISet {
int _empID;
string _empName;
public void AcceptDetails(int valOne, string valTwo) {
_empID = valOne;
_empName = valTwo;
}
static void Main(string[] args) {
Employee objEmployee = new Employee();
objEmployee.AcceptDetails(10, "Jack");
IGet objGet = objEmployee as IGet;
if (objGet != null) {
objGet.Display();
} else {
Console.WriteLine("Invalid casting occurred");
}
}
}
Đoạn mã trên định nghĩa interface ISet với phương thức AcceptDetails có hai tham số và interface IGet với phương thức Display(). Lớp Employee triển khai interface ISet và triển khai phương thức được khai báo trong ISet. Phương thức Main() tạo một thể hiện của lớp Employee. Một cố gắng được thực hiện để lấy một thể hiện của interface IGet và kiểm tra xem lớp Employee có triển khai các phương thức được xác định trong interface hay không. Vì toán tử as trả về null, mã sẽ hiển thị thông báo lỗi cụ thể.
Hình bên dưới hiển thị kết quả của ví dụ sử dụng toán tử as.
Lớp trừu tượng và Interface
Cả lớp trừu tượng và interface đều khai báo phương thức mà không triển khai chúng. Mặc dù cả lớp trừu tượng và interface có những đặc điểm tương tự nhau, nhưng chúng phục vụ mục đích khác nhau trong một ứng dụng C#.
Cả lớp trừu tượng và interface đều chứa các phương thức trừu tượng được triển khai bởi lớp kế thừa. Tuy nhiên, một lớp trừu tượng có thể kế thừa một lớp khác trong khi một interface không thể kế thừa một lớp. Do đó, lớp trừu tượng và interface có những điểm tương đồng cũng như những khác biệt nhất định.
Điểm tương đồng
Các điểm tương đồng giữa lớp trừu tượng và interface như sau:
- Cả lớp trừu tượng lẫn interface đều không thể được khởi tạo.
- Cả lớp trừu tượng và interface đều chứa các phương thức trừu tượng. Các phương thức trừu tượng của cả lớp trừu tượng lẫn interface đều được triển khai bởi lớp con kế thừa.
- Cả lớp trừu tượng lẫn interface đều có thể kế thừa nhiều interface.
Sự khác biệt
Cả lớp trừu tượng và giao diện đều tương tự nhau vì cả hai đều chứa các phương thức trừu tượng được thực hiện bởi lớp kế thừa. Tuy nhiên, có những sự khác biệt nhất định giữa một lớp trừu tượng và một giao diện.
Bảng bên dưới liệt kê sự khác biệt giữa hai loại này.
Giao Diện (Interfaces) | Lớp Trừu Tượng (Abstract Classes) |
Một lớp trừu tượng có thể kế thừa một lớp và nhiều giao diện. | Một giao diện có thể kế thừa nhiều giao diện nhưng không thể kế thừa một lớp. |
Một lớp trừu tượng có thể có các phương thức có thân. | Một giao diện không thể có các phương thức có thân. |
Phương thức của lớp trừu tượng được triển khai bằng từ khóa override. | Phương thức của giao diện được triển khai mà không sử dụng từ khóa override. |
Một lớp trừu tượng là lựa chọn tốt khi bạn cần thực hiện các phương thức chung và khai báo các phương thức trừu tượng chung. | Một giao diện là lựa chọn tốt khi bạn chỉ cần khai báo các phương thức trừu tượng. |
Một lớp trừu tượng có thể khai báo hàm dựng và hàm hủy. | Một giao diện không thể khai báo hàm dựng hoặc hàm hủy. |
Đề xuất sử dụng lớp Trừu Tượng và Giao Diện
Có một số hướng dẫn để quyết định khi nào nên sử dụng giao diện và khi nào nên sử dụng lớp trừu tượng. Đó là:
- Nếu một lập trình viên muốn tạo các chương trình có thể tái sử dụng và duy trì nhiều phiên bản của chúng, nên tạo một lớp trừu tượng. Lớp trừu tượng giúp duy trì phiên bản của chương trình một cách đơn giản. Điều này bởi vì bằng cách cập nhật lớp cơ sở, tất cả các lớp kế thừa sẽ được cập nhật tự động với sự thay đổi cần thiết. Không giống như lớp trừu tượng, giao diện không thể thay đổi sau khi được tạo. Một giao diện mới phải được tạo để tạo phiên bản mới của giao diện hiện tại.
- Nếu một lập trình viên muốn tạo ra các phương thức khác nhau hữu ích cho nhiều loại đối tượng khác nhau, nên tạo một giao diện. Điều này bởi vì lớp trừu tượng thường chỉ được tạo ra cho các đối tượng có liên quan. Phải có một mối quan hệ giữa lớp trừu tượng và các lớp kế thừa lớp trừu tượng. Ngược lại, giao diện phù hợp cho việc thực hiện các chức năng tương tự trong các lớp không giống nhau.