Lớp Trừu Tượng & Giao Diện: Hướng Dẫn Toàn Tập trong Lập Trình Hướng Đối Tượng (OOP)

Thiện Khang 17/06/2025 16

Khám phá chi tiết về lớp trừu tượng (abstract class) và giao diện (interface) trong lập trình hướng đối tượng. Tìm hiểu sự khác biệt, cú pháp và ứng dụng thực tế để nâng cao kỹ năng thiết kế phần mềm.

 

1. Khái Niệm Lớp Trừu Tượng

Lớp trừu tượng là một lớp đặc biệt không thể được khởi tạo trực tiếp thành đối tượng. Mục đích chính của nó là định nghĩa một khuôn mẫu chung cho các lớp con kế thừa. Nó chứa:

  • Các phương thức trừu tượng: Đây là những phương thức chỉ có khai báo (signature) mà không có phần thân (implementation). Các lớp con bắt buộc phải triển khai (override) các phương thức này.
  • Các phương thức và thuộc tính thông thường: Lớp trừu tượng có thể chứa các thành phần có cài đặt đầy đủ, được chia sẻ cho tất cả các lớp con.

Vai trò quan trọng của lớp trừu tượng:

  • Kiểm soát cấu trúc: Giúp người quản lý dự án hoặc kiến trúc sư phần mềm định hình cấu trúc ứng dụng, đảm bảo các lập trình viên tuân thủ một bộ quy tắc nhất định.
  • Buộc triển khai: Bằng cách khai báo các phương thức trừu tượng, lớp trừu tượng buộc các lớp con phải cung cấp cài đặt cụ thể cho những hành vi cần thiết.
  • Khái quát hóa ý tưởng: Thể hiện những ý tưởng chung, chưa hoàn chỉnh mà các lớp con sẽ tiếp tục phát triển và hoàn thiện.

2. Cú Pháp

Để khai báo một lớp trừu tượng, bạn sử dụng từ khóa abstract:

abstract class <Tên_Lớp_Trừu_Tượng>
{
   // Khai báo thuộc tính trừu tượng
   public abstract String <Tên_Thuộc_Tính>
   {
       get;
       set;
   }

   // Khai báo phương thức trừu tượng (không có thân)
   public abstract String <Tên_Phương_Thức>(..);

   // Có thể có các phương thức và thuộc tính không trừu tượng
   public void DisplayMessage()
   {
       Console.WriteLine("Đây là phương thức không trừu tượng.");
   }
}

public abstract class AbsClass
{
   String path;
   public String Path
   {
       get { return path; }
       set { path = value; }
   }

   public abstract String[] GetData(); // Phương thức trừu tượng

   public static String[] GetDriver() // Phương thức tĩnh (không trừu tượng)
   {
       return Directory.GetLogicalDrives();
   }
}

public abstract class AbsClass
{
   String path;
   public String Path
   {
       get { return path; }
       set { path = value; }
   }

   public abstract String[] GetData(); // Phương thức trừu tượng

   public static String[] GetDriver() // Phương thức tĩnh (không trừu tượng)
   {
       return Directory.GetLogicalDrives();
   }
}

3. Xây Dựng Lớp Kế Thừa Giao Diện

Khi một lớp kế thừa (hay đúng hơn là triển khai) một giao diện, nó bắt buộc phải định nghĩa tất cả các thành phần đã khai báo trong giao diện đó.

Kế thừa một giao diện:

public class CClass : InterfaceX // Triển khai InterfaceX
{
   Int32 ax, bx;

   public Int32 a // Triển khai thuộc tính a từ InterfaceX
   {
       get { return ax; }
       set { ax = value; }
   }

   public Int32 b // Triển khai thuộc tính b từ InterfaceX
   {
       get { return bx; }
       set { bx = value; }
   }

   public void Method_i() // Triển khai phương thức Method_i từ InterfaceX
   {
       Console.WriteLine("Method i");
   }

   public void Method_j() // Triển khai phương thức Method_j từ InterfaceX
   {
       Console.WriteLine("Method j");
   }

   public void Method_0() // Phương thức riêng của CClass
   {
       Console.WriteLine("Method 0");
   }
}

Kế thừa nhiều giao diện:

Một lớp có thể triển khai nhiều giao diện cùng lúc. Điều này cho phép lớp đó có nhiều "vai trò" hoặc "bộ mặt".

public class CClass : InterfaceX, InterfaceY // Triển khai cả InterfaceX và InterfaceY
{
   Int32 ax, bx, cx;

   public Int32 a { get { return ax; } set { ax = value; } }
   public Int32 b { get { return bx; } set { bx = value; } }
   public Int32 c { get { return cx; } set { cx = value; } } // Từ InterfaceY

   public void Method_i() { Console.WriteLine("Method i"); } // Từ InterfaceX
   public void Method_j() { Console.WriteLine("Method j"); } // Từ cả InterfaceX và InterfaceY
   public void Method_k() { Console.WriteLine("Method k"); } // Từ InterfaceY

   public void Method_0() { Console.WriteLine("Method 0"); }
}

4. Sử Dụng Giao Diện

Để sử dụng các thành phần của một lớp thông qua giao diện, bạn cần ép kiểu đối tượng về kiểu giao diện đó. Điều này cho phép bạn tương tác với đối tượng dựa trên "hợp đồng" mà giao diện định nghĩa, mà không cần biết chi tiết về lớp cài đặt cụ thể.

Khi bạn ép kiểu một đối tượng sang một giao diện, bạn chỉ có thể truy cập các thành phần được định nghĩa trong giao diện đó. Các thành phần khác của lớp cài đặt sẽ bị "che giấu".

5. Xây Dựng Giao Diện Kế Thừa Giao Diện Khác

Giao diện cũng có thể kế thừa từ một hoặc nhiều giao diện khác. Điều này tạo ra một "hợp đồng" lớn hơn, bao gồm tất cả các thành phần của các giao diện cha.

interface <Tên_Giao_Diện_Mới> : <Interface_Cha_1>, <Interface_Cha_2>
{
   // Khai báo thành phần riêng của giao diện này
}

Lưu ý:

  • Có thể kế thừa đơn, đa kế thừa (tức là một giao diện có thể kế thừa từ nhiều giao diện khác), và kế thừa nhiều cấp.
  • Lớp triển khai giao diện con phải định nghĩa đầy đủ tất cả các thành phần của giao diện con và cả các giao diện mà nó kế thừa.

Khác Biệt Giữa Lớp Trừu Tượng và Giao Diện

Đặc điểmLớp Trừu Tượng (Abstract Class)Giao Diện (Interface)
Khởi tạo đối tượngKhông thể khởi tạo trực tiếp.Không thể khởi tạo trực tiếp.
Thành phầnCó thể chứa phương thức trừu tượng, phương thức có thân, thuộc tính, trường, constructor...Chỉ chứa các thành phần trừu tượng: phương thức, thuộc tính, sự kiện. Không có trường (fields).
Tính staticCó thể chứa thành phần static (không trừu tượng).Không thể chứa thành phần static.
Đa kế thừaMột lớp chỉ có thể kế thừa duy nhất một lớp trừu tượng.Một lớp có thể triển khai nhiều giao diện.
Mục đíchĐịnh nghĩa một "là một loại" (is-a kind of) quan hệ. Thường dùng cho các lớp có chung cài đặt cơ bản hoặc chia sẻ hành vi chung.Định nghĩa một "có khả năng làm được" (can-do) quan hệ. Thường dùng để mô tả các chức năng hoặc hành vi mà một lớp có thể thực hiện, không quan tâm đến cách nó được triển khai.
Mức độ linh hoạtÍt linh hoạt hơn trong đa kế thừa.Rất linh hoạt, cho phép một đối tượng có nhiều "vai trò".
Mối quan hệĐịnh nghĩa mối quan hệ "cha-con" chặt chẽ hơn.Định nghĩa mối quan hệ "hợp đồng" lỏng lẻo hơn.

Tóm lại:

  • Sử dụng lớp trừu tượng khi bạn muốn định nghĩa một khuôn mẫu chung cho một nhóm các lớp có chung hành vi cơ bản và một số cài đặt mặc định.
  • Sử dụng giao diện khi bạn muốn định nghĩa một tập hợp các hành vi mà một lớp có thể cam kết thực hiện, cho phép linh hoạt trong việc tạo ra các đối tượng đa năng và tuân thủ nhiều "hợp đồng" khác nhau.

Việc hiểu rõ và áp dụng đúng lớp trừu tượng và giao diện sẽ giúp bạn xây dựng các hệ thống phần mềm mạnh mẽ, dễ quản lý và mở rộng trong lập trình hướng đối tượng.