它一如既往地依賴於問題。我使用接口來定義這組類的用戶界面。至少當我知道我將有不止一個實現基礎實際類的實現時。例如你可以有這樣的事情:
IAllInterfaced = interface(IInterface)
procedure ImplementMeEverywhere_1(const Params: TParams);
procedure ImplementMeEverywhere_2(const Params: TParams);
procedure ImplementMeEverywhere_3(const Params: TParams);
end;
TAllInterfaced_ClassA = class(TInterfacedObject, IAllInterfaced)
public
procedure ImplementMeEverywhere_1(const Params: TParams);
procedure ImplementMeEverywhere_2(const Params: TParams);
procedure ImplementMeEverywhere_3(const Params: TParams);
end;
TAllInterfaced_ClassB = class(TInterfacedObject, IAllInterfaced)
public
procedure ImplementMeEverywhere_1(const Params: TParams);
procedure ImplementMeEverywhere_2(const Params: TParams);
procedure ImplementMeEverywhere_3(const Params: TParams);
end;
在這裏你沒有共同的祖先。每個類只實現了接口,並且沒有公共基礎類的通用基礎結構。如果實現如此不同以至於它們不共享任何內容,但是他可以自行連接,這是可能的。您仍然需要使用相同的界面,以便您對派生類的用戶保持一致。
第二個選項是:
IAllAbstract = interface(IInterface)
procedure ImplementMeEverywhere_1(const Params: TParams);
procedure ImplementMeEverywhere_2(const Params: TParams);
procedure ImplementMeEverywhere_3(const Params: TParams);
end;
TAllAbstract_Custom = (TInterfacedObject, IAllAbstract)
private
...
public
procedure ImplementMeEverywhere_1(const Params: TParams); virtual; abstract;
procedure ImplementMeEverywhere_2(const Params: TParams); virtual; abstract;
procedure ImplementMeEverywhere_3(const Params: TParams); virtual; abstract;
end;
TAllAbstract_ClassA = class(TAllAbstract_Custom)
public
procedure ImplementMeEverywhere_1(const Params: TParams); override;
procedure ImplementMeEverywhere_2(const Params: TParams); override;
procedure ImplementMeEverywhere_3(const Params: TParams); override;
end;
TAllAbstract_ClassB = class(TAllAbstract_Custom)
public
procedure ImplementMeEverywhere_1(const Params: TParams); override;
procedure ImplementMeEverywhere_2(const Params: TParams); override;
procedure ImplementMeEverywhere_3(const Params: TParams); override;
end;
這裏有一個基類中的所有類。在那個類中,你可以有共同的屬性或事件其他類等等。但是所有的過程都被標記爲抽象的,因爲它們不執行任何常見的任務。摘要確保它們將在派生類中實現,但不需要在每個類中實現「FieldA」,只需在「TAllAbstract_Custom」中實現它。這確保使用DRY原則。
最後一個選項是:
IAllVirtual = interface(IInterface)
procedure ImplementMeEverywhere_1(const Params: TParams);
procedure ImplementMeEverywhere_2(const Params: TParams);
procedure ImplementMeEverywhere_3(const Params: TParams);
end;
TAllVirtual_Custom = (TInterfacedObject, IAllVirtual)
private
...
public
procedure ImplementMeEverywhere_1(const Params: TParams); virtual;
procedure ImplementMeEverywhere_2(const Params: TParams); virtual;
procedure ImplementMeEverywhere_3(const Params: TParams); virtual;
end;
TAllVirtual_ClassA = class(TAllVirtual_Custom)
public
procedure ImplementMeEverywhere_1(const Params: TParams); override;
procedure ImplementMeEverywhere_2(const Params: TParams); override;
procedure ImplementMeEverywhere_3(const Params: TParams); override;
end;
TAllVirtual_ClassB = class(TAllVirtual_Custom)
public
procedure ImplementMeEverywhere_1(const Params: TParams); override;
procedure ImplementMeEverywhere_2(const Params: TParams); override;
procedure ImplementMeEverywhere_3(const Params: TParams); override;
end;
這裏所有派生類都有一個共同的基礎虛擬程序。這可以確保您不必在派生類級別實現每個過程。您只能覆蓋代碼的某些部分,或者根本沒有。
當然,這都是邊緣案例,它們在甜頭圈的地方還有空間。你可以混合使用這些概念。
只需記住:
- 接口是確保你從用戶隱藏實現功能強大的工具,你有一個常見的用法點(接口)。他們還強制使用一些規範,因爲接口需要全面實施。
- 摘要是一個很好的工具,因此您不必爲空的存根使用沒有真正需要的過程。另一方面,他們強迫你在派生類中實現它們。
- 當你有必須由每個類實現的通用代碼並確保OP和DRY乾淨原則的時候,虛擬就派上用場了。當你有不是每個派生類都有或需要的程序時,他們也是受歡迎的。
對不起,很長的回答,但我不能在這裏給一個簡單的解釋,因爲沒有。這一切都取決於手頭的問題。它是派生類共有多少和它們的實現有多不同之間的一種平衡。
我只是想知道,如果我的耐火材料實際上是耐火材料,或只是干預。大多數情況下,將代碼保持原樣並讓Delphi自動完成我的函數並繼承,讓Delphi在未實現抽象函數時提醒我會更簡單。我改變它的唯一原因是因爲當我添加新的子類時,我正在複製並粘貼一個巨大的界面部分(這只是越來越大, – 2010-09-27 16:24:03