Interface (giao diện - nhưng mình thích dùng từ interface hơn) là tập hợp các method và property, dùng để mô tả hành vi của một loại lớp nhất định nào đó. Interface có thể được gắn vào một class, khi đó class bắt buộc phải triển khai những gì interface khai báo. Nói cách khác, interface là một bộ quy tắc ràng buộc, khi được gắn vào một class, class đó phải bắt buộc tuân theo.
Interface có lẽ khá giống với abstract class. Cả hai cùng ràng buộc những gì mà class cần phải có. Khi kế thừa abstract class, lớp con phải thực hiện tất cả các abstract method. Khi class được gắn interface, class phải thực hiện tất cả các method của interface. Nhìn khá giống nhau nhưng có một số khác biệt:
Một class chỉ có thể liên kết với một abstract method (là lớp cha), nhưng có thể được gắn nhiều interface.
Interface bắt buộc mọi class được gắn interface phải triển khai các method đã khai báo, trong khi với abstract class, lớp con có thể thực hiện hoặc không
Lưu ý: Interface chỉ chứa được các method và property, không chứa field và property dạng field. Bên cạnh đó, mọi thành phần trong interface đều phải được công khai (access modifier mặc định là public, bạn không thể thay đổi)
Interface có thể kế thừa như class.
Ví dụ như, chúng ta có một lớp xe. Đã là xe thì phải có thể chạy (method Run), và có bánh xe (thuộc tính SoBanhXe). Chúng ta sử dụng một interface IXe (tên interface được đặt với chữ cái I đầu tiên).
type
IXe = interface
procedure Run;
function SoBanhXe: Byte;
end;
Tiếp theo, chúng ta có các class như TXeHoi.
type
TXeHoi = class(TInterfacedObject, IXe)
procedure Run;
function SoBanhXe: Byte;
end;
procedure TXeHoi.Run;
begin
writeln('Xe hoi dang chay');
end;
function TXeHoi.SoBanhXe: byte;
begin
Result := 4;
end;
Như vậy, class TXeHoi được gắn interface IXe, nên bắt buộc những method nào có trong interface IXe đều phải có trong class TXeHoi.
Trong code trên, chúng ta kế thừa lớp TXeHoi từ một lớp TInterfacedObject. Lớp này cho phép class được gắn với interface. Phía sau TInterfacedObject là danh sách các interface được gắn thêm vào class.
Bên cạnh những ưu điểm đã đề cập, một ưu điểm khác của interface và abstract class là tính phân loại cao hơn. Vì lớp chỉ có thể kế thừa một abstract class, nên mọi method cần thiết phải được đặt trong abstract class đó. Nhưng, sẽ có những method không liên quan với nhau nằm chung một class cha, nên sẽ làm giản tính phân loại, và giảm khả năng mở rộng cho nhiều class.
Interface thì khác, mỗi interface quy định một chức năng cụ thể khác nhau, bạn có thể gắn nhiều interface vào một class. Điều đó giúp tách bạch các quy tắc ra rõ ràng cho từng loại hơn. Và bạn có thể dễ dàng mở rộng các class bằng việc kết hợp các interface.
Ví dụ đi, bạn có một lớp TMayBayBoeing (máy bay boeing). Là máy bay phải có thể bay (method Fly), và là máy móc (method Working).
Bạn có thể sử dụng 2 interface ICanFly và IMachine như sau, rồi gắn vào class TMayBay.
type
ICanFly = interface
procedure Fly;
end;
IMachine = interface
procedure Working;
end;
TMayBayBoeing = class(TInterfacedObject, IMachine, ICanFly);
procedure Fly;
procedure Working;
end;
procedure TMayBayBoeing.Fly;
begin
writeln('May bay dang bay');
end;
procedure TMayBayBoeing.Working;
begin
writeln('Dong co may bay dang lam viec');
end;
Hoặc sử dụng abstract class
type
TMayBay = class
procedure Fly; virtual; abstract;
procedure Working; virtual; abstract;
end;
TMayBayBoeing = class(TMayBay)
procedure Fly; override;
procedure Working; override;
end;
procedure TMayBayBoeing.Fly;
begin
writeln('May bay dang bay');
end;
procedure TMayBayBoeing.Working;
begin
writeln('Dong co may bay dang lam viec');
end;
Với abstract class, bạn thấy Fly và Working chả có liên quan gì với nhau, thế mà vẫn ở chung một class TMayBay. Bây giờ, hãy thử khai báo thêm class TChimSe để mô tả loài chim sẻ. Loài chim sẽ có thể bay (Fly). Với abstract class, bạn phải tạo một class TChim mới với method Fly, từ đó kế thừa TChim thành TChimSe như sau:
type
TChim = class
procedure Fly; virtual; abstract;
end;
TChimSe = class(TChim)
procedure Fly; override;
end;
procedure TChimSe.Fly;
begin
writeln('Hoa mi dang bay');
end;
Nhưng với interface, những gì bạn cần làm chỉ là gắn interface ICanFly vào class TChimSe và triển khai nó thôi.
type
TChimSe = class(TInterfacedObject, ICanFly)
procedure Fly;
end;
procedure TChimSe.Fly;
begin
writeln('Chim se dang bay');
end;
Bạn đã hiểu được lợi ích của interface so với abstract class chưa ?
GUID là một đoạn mã ngắn có dạng {EBA0AD80-F22B-4C30-B6AF-743FDDB03426}, dùng để xác định một đối tượng duy nhất trên toàn cầu. Có rất rất nhiều GUID nên tỉ lệ hai đối tượng có cùng GUID là rất thấp.
Interface cũng là một đối tượng, và cũng có GUID. Sở dĩ interface có GUID mà class không có vì interface định nghĩa các hành vi đặc trưng của đối tượng, nên có thể đại diện cho đối tượng, còn class thì không.
type
IXe = interface
['{EBA0AD80-F22B-4C30-B6AF-743FDDB03426}']
procedure Run;
function SoBanhXe: Byte;
end;
Khai báo GUID cho interface như ở trên ví dụ, vị trí đặt ở sau từ khóa interface.
Vậy làm sao để có được GUID ? Rất đơn giản, khi bạn viết mã cho interface, chỉ cần nhấn tổ hợp phím Ctrl + Shift + G, IDE sẽ tự động chèn vào đó một GUID mới hoàn toàn.
GUID có ý nghĩa khá quan trọng trong lập trình COM và ActiveX, nếu bạn chưa biết lập trình COM và ActiveX là gì thì GUID không nên được quan tâm quá sâu.
Với interface, bạn có thể viết mã mà không cần quan tâm đến loại đối tượng. Ví dụ như đi xe, bạn chỉ cần biết đó là xe, không cần quan tâm đến xe gì cả.
type
IXe = interface
procedure Run;
end;
TXeHoi = class(TInterfacedObject, IXe)
procedure Run;
end;
TXeDap = class(TInterfacedObject, IXe)
procedure Run;
end;
procedure TXeHoi.Run;
begin
writeln('Xe hoi dang chay');
end;
procedure TXeDap.Run;
begin
writeln('Xe dap dang chay');
end;
var
Xe: IXe;
begin
if IAmRich = true then
Xe := TXeHoi.Create
else
Xe := TXeDap.Create;
Xe.Run;
end;
Điều này giá giống với tính đa hình của OOP.
Đoạn code không sử dụng đa hình (do không có lớp cha trừu tượng), không sử dụng object, thay vào đó dùng interface thay cho object. Lưu ý, interface chỉ thực thi được những gì được khai báo của interface, không phải của class.
Interface là một chủ đề rất rộng trong delphi OOP. Bạn có thể tự tìm hiểu thêm ...