それはいつものように問題に依存します。インターフェイスを使用して、一連のクラスのユーザー インターフェイスを定義します。少なくとも、基礎となる実際のクラスの実装が複数あることがわかっている場合。たとえば、次のようなものがあります。
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;
ここでは、共通の祖先はありません。各クラスはインターフェイスを実装するだけで、共通の基本クラスの形式で共通の基礎となる構造を持ちません。これは、実装が非常に異なっていて何も共有していない場合に可能ですが、彼はそれ自体をインターフェースします。派生クラスのユーザーに対して一貫性を保つために、同じインターフェイスを使用する必要があります。
2 番目のオプションは次のとおりです。
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」を実装する必要はなく、「TAAllAbstract_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;
ここでは、すべての派生クラスに共通の基本仮想プロシージャがあります。これにより、派生クラスのレベルですべての手順を実装する必要がなくなります。コードの一部のみをオーバーライドするか、まったくオーバーライドできません。
当然のことながら、これはすべて特殊なケースであり、それらを回避する余地があります。これらの概念を混在させることができます。
覚えとけ:
- インターフェイスは、実装をユーザーから隠し、共通の使用ポイント (インターフェイス) を確保するための強力なツールです。また、インターフェイスを完全に実装する必要があるため、いくつかの規範の使用を強制します。
- 抽象は優れたツールであるため、実際には必要のない手順に空のスタブを使用する必要はありません。反対に、それらは派生クラスでそれらを実装することを強制します。
- Virtual は、すべてのクラスで実装する必要があり、明確な OP および DRY 原則を保証する共通コードがある場合に便利です。すべての派生クラスが持っている、または必要としないプロシージャがある場合にも歓迎されます。
長い回答で申し訳ありませんが、ここには簡単な説明がありません。それはすべて当面の問題に依存します。派生クラスの共通点と実装の違いのバランスです。