C# - C Sharp: Abstract class & Interface

Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực

Lớp trừu tượng (Abstract class)

Giới thiệu

C# cho phép thiết kế một loại lớp đặc biệt được sử dụng khá tương tự như lớp thông thường, đó là Lớp trừu tượng (Abstract class). Loại lớp này có thể được tham chiếu như là lớp cơ sở không hoàn chỉnh, nó không được có phần thể hiện (không tạo được đối tượng từ lớp trừu tượng), nó vẫn được quyền thừa kế từ lớp khác và cho phép các lớp khác thừa kế nó.

Vậy mục đích của việc tạo ra lớp trừu tượng để làm gì? Tôi có một lớp Động vật (Animal), đương nhiên đã là động vật thì phải ăn mới tồn tại, tức là sẽ xuất hiện hành vi ăn, nhưng những loài vật khác nhau thì hành vi ăn cũng như loại thức ăn là khác nhau, chẳng hạn như lớp gia súc thì ăn cỏ, lớp động vật họ mèo thì ăn thịt. Vì thế nếu lớp Động vật được xây dựng là lớp thông thường thì khi ta định nghĩa phương thức ăn chắc chắn rằng sẽ không thể miêu tả được hành vi ăn cũng như loại thức ăn đặc trưng của tường loài. Trong trường hợp này ta xây dựng lớp Động vật là loại lớp trừu tượng và phương thức ăn ta khai báo là phương thức trừu tượng, nghĩa là không định nghĩa cụ thể, và điều này sẽ được nhường cho các lớp động vật khác nhau thừa kế từ Động vật thực thi cụ thể. Như vậy, lớp trừu tượng sẽ khai báo các phương thức chung cho tất cả các lớp dẫn xuất (thừa kế từ nó), những lớp này phải có nhiệm vụ thực thi phương thức đó nhưng theo cách thức riêng của từng lớp.

Khai báo

Lớp trừu tượng được khai báo bằng cách sử dụng từ khóa abstract và có thể có hoặc không những thành phần sau: các thành phần dữ liệu thông thường, các phương thức thông thường và các phương thức trừu tượng.

abstract class Tên_lớp {
  //Khai báo các trường
  //Định nghĩa các phương thức thông thường
  //Khai báo các phương thức trừu tượng.
}

Khi tạo một lớp trừu tượng bạn cần lưu ý các vấn đề sau:

- Thứ nhất: Không được sử dụng từ khoá sealed (nhằm mục đích không cho thừa kế). Ví dụ, cách tạo lớp trừu tượng như sau là sai:

abstract sealed class Animal { //sai vì sử dụng từ khoá sealed
}

- Thứ hai: Bổ từ truy cập của phương thức trừu tượng không được là private. Ví dụ sau đây là sai khi tạo phương thức trừu tượng:

private abstract void Move(); //sai vì bổ từ truy cập là private

- Thứ ba: Phương thức trừu tượng chỉ có thể được khai báo trong lớp trừu tượng hoặc interface. Ví dụ sau đây là sai khi đặt phương thức trừu tượng trong lớp thông thường:

class A {
  public abstract void demo(); //sai vì đặt phương thức trừu tượng trong lớp không trừu tượng
}

- Thứ tư: Bổ từ truy cập của phương thức trừu tượng là gì thì ở phần thực thi phương thức trừu tượng trong lớp dẫn xuất cũng là như vậy. Ví dụ sau đây là sai khi có sự khác nhau về bổ từ truy cập đối với phương thức trừu tượng:

abstract class A {
  protected abstract void demo();
}
class B : A {
  public override void demo() { //sai bổ từ truy cập
}
}

- Thứ năm: Không được sử dụng từ khoá virtual khi khai báo phương thức trừu tượng vì ngầm định phương thức trừu tượng đã là virtual. Ví dụ sau đây là sai vì sử dụng từ khoá virtual khi khai báo phương thức trừu tượng:

abstract class A {
  public abstract virtual void demo(); //sai, bạn không được dùng virtual khi khai báo phương thức trừu tượng
}

- Thứ sáu: Các thành phần trừu tượng trong lớp trừu tượng không được khai báo là static. Ví dụ sau đây là sai:

abstract class A {
  public abstract static void demo(); //sai, bạn không được dùng static khi khai báo phương thức trừu tượng
}

Áp dụng

Nhắc lại rằng khi trong lớp trừu tượng đã có phương thức trừu tượng thì bắt buộc những lớp thừa kế từ nó phải thực thi phương thức này. Ví dụ:

abstract class A {
  protected abtract void demo(); //Lớp A có phương thức trừu tượng
}
class B:A { //Lớp B thừa kế lớp A
  protected override void demo() { //thì bắt buộc B phải thực thi phương thức trừu tượng của A
  }
}

Đoạn mã dưới đây minh họa việc khai báo và thực thi một lớp trừu tượng.

using System;
abstract class DongVat {
  public void An() {
    Console.WriteLine("Dong vat phai an thuc an de ton tai");
  }
  public abstract void tiengKeu();
}
class SuTu : DongVat {
  public override void TiengKeu() {
    Console.WriteLine("Su tu gam");
  }
  static void Main(string[] args) {
    SuTu objSuTu = new SuTu();
    objSuTu.tiengKeu();
    objSuTu.An();
  }
}

Giải thích đoạn mã: Lớp trừu tượng DongVat được khai báo và lớp SuTu thừa kế từ nó. Vì trong lớp DongVat khai báo phương thức trừu tượng là tiengKeu(), nên lớp Sutu sẽ ghi đè phương thức này thông qua từ khóa override và thực thi nó. Phương thức Main() của lớp SuTu tiến hành gọi phương thức TiengKeu()An() sử dụng toán tử dấu chấm (.).

Giao diện (Interface)

C# không cho phép một lớp thừa kế nhiều lớp, nghĩa là nó không hỗ trợ đa thừa kế. Để khắc phục điều này thì C# đưa ra phương pháp gọi là Giao diện (Interface).

Theo đó, một lớp có thể thừa kế từ một lớp khác, đồng thời thừa kế từ nhiều interface khác nhau. Ở đây có điểm cần lưu ý là lớp được thừa kế phải đặt trước các interface. Ví dụ:

interface IA {
}
interface IB {
}
class A {
}
class B : A, IA, IB { //nếu đặt lớp A sau một interface nào đó thì trình dịch sẽ báo lỗi
}

Interface không được chứa các trường, mà chỉ có thể chứa các khai báo Property. Property phải có ít nhất một bộ truy cập (accessor) và bạn chỉ được khai báo mà không được định nghĩa accessor.

Interface cũng chỉ được phép khai báo các phương thức mà không được định nghĩa chúng.

Tất cả các thành phần của interface đều phải là public và đây là mặc định.

Sau đây là cú pháp tạo interface:

interface Tên_interface {
  Kiểu_dữ_liệu Tên_property //khai báo Property
  {
    get;
    set;
  }
  ...
  Kiểu_trả_về Tên_phương_thức(); //khai báo phương thức
  ...
}

Ví dụ:

interface IA {
  int Number {
    get;
    set;
  }
  void demo();
}

Lớp thừa kế interface bắt buộc phải thực thi tất cả các thành phần của interface, bao gồm cả Property và các phương thức của nó. Ví dụ:

interface IA {
  int Number {
    get;
    set;
  }
  void demo();
  }
class A:IA {
  int number;
  public int Number {
    get {
      return number;
    }
    set {
      number = value;
    }
  }
  public void demo() {
  }
}

Lưu ý: Interface không được có phần thể hiện (không có đối tượng), được quyền thừa kế từ các interface khác nhưng không thừa kế được từ lớp.

So sánh abstract class và interface

Giống nhau:

+ Không có thể hiện.

+ Chứa các phương thức trừu tượng.

+ Các phương thức trừu tượng được thực thi ở lớp con.

+ Thừa kế từ nhiều interface.

Khác nhau:

+ Lớp trừu tượng thừa kế từ một lớp và nhiều interface, interface chỉ thừa kế được từ nhiều interface mà không thừa kế được lớp.

+ Lớp trừu tượng định nghĩa được phương thức, interface không định nghĩa được phương thức.

+ Phương thức trừu tượng của lớp trừu tượng được thực thi bằng cách dùng từ khóa override, còn interface thì không cần nhưng bổ từ truy cập phải là public.

+ Lớp trừu tượng là lựa chọn khi bạn muốn vừa khai báo vừa định nghĩa phương thức, interface là lựa chọn phù hợp hơn khi bạn chỉ muốn khai báo các phương thức.

+ Lớp trừu tượng có hàm tạo và hàm hủy, interface không có hàm tạo và hàm hủy.

» Tiếp: Từ khóa base
« Trước: Interface
Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực
Copied !!!