Delphi 介面中只能聲明方法與屬性,不能聲明字段。因此介面屬性的 read/write 必須映射到方法,而非字段。實現類負責提供存儲字段與讀寫方法,屬性語義歸屬於介面契約。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
// 1. 介面聲明屬性 Name,讀寫映射到方法
INameable = interface
['{B2C3D4E5-F6A7-8901-BCDE-F23456789012}']
function GetName: string;
procedure SetName(const Value: string);
property Name: string read GetName write SetName;
end;
// 2. 實現類提供字段存儲與方法實現
TNamedObject = class(TInterfacedObject, INameable)
private
FName: string; // 實際存儲字段,介面不可見
public
function GetName: string;
procedure SetName(const Value: string);
end;
TForm1 = class(TForm)
btnTest: TButton;
procedure btnTestClick(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TNamedObject }
function TNamedObject.GetName: string;
begin
Result := FName;
end;
procedure TNamedObject.SetName(const Value: string);
begin
FName := Value;
end;
{ TForm1 }
procedure TForm1.btnTestClick(Sender: TObject);
var
Obj: TNamedObject;
Intf: INameable;
begin
Obj := TNamedObject.Create;
Intf := Obj; // 隱式轉換,RefCount=1
// 僅通過介面訪問屬性
Intf.Name := 'ABC';
ShowMessage('介面讀取: ' + Intf.Name); // ABC
// 編譯錯誤:Obj.Name 不存在(屬性屬於介面,不屬於類)
// ShowMessage(Obj.Name);
// 驗證類內部字段確實被修改
ShowMessage('類字段直接讀: ' + Obj.FName); // ABC (若 FName 為 public/protected)
// Intf 離開作用域自動釋放 Obj
end;
end.
| 規則 | 說明 |
|---|---|
| 介面無字段 | 不能在介面中聲明 FName: string; |
| 屬性讀寫必須是方法 | read GetName write SetName,不能 read FName |
| 方法可在介面聲明也可只在類實現 | 介面聲明則成契約一部分;類私有實現則屬實現細節 |
| 屬性歸屬介面 | 類實例無該屬性,只能通過介面引用訪問 |
| 實現類自行管理存儲 | 字段、屬性包裝、計算屬性、委託其他對象皆可 |
type
IReadOnlyInfo = interface
function GetFullName: string;
function GetAge: Integer;
property FullName: string read GetFullName; // 唯讀計算屬性
property Age: Integer read GetAge;
end;
TPerson = class(TInterfacedObject, IReadOnlyInfo)
private
FFirstName, FLastName: string;
FBirthDate: TDate;
public
function GetFullName: string;
function GetAge: Integer;
end;
function TPerson.GetFullName: string;
begin
Result := FFirstName + ' ' + FLastName; // 計算屬性,無存儲字段
end;
function TPerson.GetAge: Integer;
begin
Result := YearsBetween(Date, FBirthDate); // 委託計算
end;
| 維度 | 類屬性 | 介面屬性 |
|---|---|---|
| 存儲 | 可直接映射字段 | 必須映射方法 |
| 可見性 | public/protected/private/published | 隱式 public(介面無訪問控制) |
| RTTI | 完整支援 (published) | 僅方法有 RTTI,屬性本身無 |
| 繼承 | 單繼承,可覆寫 | 介面可繼承介面,類實現多介面 |
| 用途 | 對象狀態封裝、IDE 設計時屬性 | 契約定義、多態訪問、跨模塊邊界 |
Obj.Name 編譯失敗,必須 (Obj as INameable).Name 或 Intf.Name。procedure SetX。property Items[Index: Integer]: string read GetItem write SetItem;,但索引類型受限。Delphi 介面屬性是純行為契約:無字段、唯方法、歸介面、實現類自管存儲。這種設計強制關注點分離——介面定義「能做什麼」,類決定「怎麼存、怎麼算」。掌握此規則,即可設計出高內聚、低耦合、易測試、易替換的介面契約體系。