ソフトウェアを設計するとき、これが「標準」のように見えるので、インターフェイスから始めました。次に、目前の問題により適していると思われる抽象クラスに切り替えました。ただし、この設計を選択する際にいくつかの考慮事項を見逃していたかどうかはわかりません。私が考えたドメイン固有の問題以外に、インターフェイスと抽象クラスを選択する際に考慮すべきより一般的な要因は何ですか?
5 に答える
継承は、構成の類似性を定義します。インターフェイスは動作の類似性を定義します。そこから、構成が動作をオーバーライドするのに十分重要かどうかを判断する必要があります。
ほとんどの場合、最良の選択肢は両方を行うことです。基本クラスで何かが起こっていることに依存している場合、それが常に可能であるとは限りません。抽象基本クラスとインターフェイスの両方を提供すると、インターフェイスの実装者によって何かが発生する必要がない限り、抽象化の実装者が最大の自由度を得ることができます。何かが起こることを必要とする場合は、インターフェイスをまったく提供したくありません-また、基本クラスがこの必要なアクションが常に発生することを保証する必要があります...
両方を行うことのマイナス: よりグー。
疑似コードの例:
interface IVehicle
{
void PutCarInGear(Int speed);
}
abstract class Vehicle : IVehicle
{
public void PutCarInGear(Int speed)
{
//base implementation
}
}
この例では、誰かが実装する独自のクラスを作成しIVehicle
、IVehicle
. Vehicle
そのオブジェクトは、抽象クラスの子である必要はありません。したがって、メソッドで何か特定のことが起こると予想した場合、PutCarInGear()
その新しいクラスはその期待を満たさない可能性が非常に高くなります。ただし、実装の内容が問題にならない限りIVehicle
、抽象基本クラスとインターフェースの両方を持つことが最も柔軟な抽象化です。
インターフェイスの少なくとも一部の機能について妥当なデフォルト動作もある場合は、抽象クラスを使用して、すべての具体的な実装で共通のボイラープレート コードを回避することをお勧めします。それ以外の場合は、インターフェースを使用してください。
テンプレート メソッド パターンを具体化するインスタンスが複数ある場合は、抽象クラスを使用します。
3 つのパーサーがあるとします。ファイルのデータを「,」で区切るもの、「 」で区切るもの、「|」で区切るものがあります。
次に、CommaParser、SpaceParser、および PipeParser をすべて持つことができます。これらはすべて、Abstract Parser をサブクラス化し、abstract メソッドをオーバーライドします。getDelimiter()
クラスが実装を共有せず、同じメソッド呼び出しに応答するだけの場合は、インターフェイスを使用します。