実装に関しては、基本型またはインターフェイスのどちらを選ぶべきですか?私はいくつかの例を試してみましたが、完全なアイデアがわかりません:(
方法と理由の例をいただければ幸いです。
抽象クラスであるかどうかに関係なく、基本クラスには実装されたメンバーを含めることができます。インターフェイスはできません。すべての実装が同様に実行される場合、すべての子クラスが基本クラスのメンバーの同じ実装を共有できるため、基本クラスが適切な方法である可能性があります。それらが実装を共有するつもりがない場合は、インターフェースが適しています。
例:
class Person
{
string Name { get; set; }
}
class Employee : Person
{
string Company { get; set; }
}
Employeeクラスは実装を共有しているため、Name
プロパティを定義する必要がないため、EmployeeがPersonから継承することは理にかなっています。
interface IPolygon
{
double CalculateArea()
}
class Rectangle : IPolygon
{
double Width { get; set; }
double Height { get; set; }
double CalculateArea()
{
return this.Width * this.Height;
}
}
class Triangle : IPolygon
{
double Base { get; set; }
double Height { get; set; }
double CalculateArea()
{
return 0.5 * this.Base * this.Height;
}
}
Rectangle
とTriangle
はCalculateArea
の実装がこのように異なるため、基本クラスから継承しても意味がありません。
基本クラスを作成し、onlyに抽象メンバーが含まれていることがわかった場合は、インターフェースを使用することもできます。
また、j__mが示すように、複数の基本クラスから継承することはできませんが、複数のインターフェースを実装することはできます。
通常、最初にインターフェイスを定義し、実装でコードが重複していることに気付いた場合は、インターフェイスを実装する基本クラスを作成し、実装にそれを継承させます。
抽象クラスとインターフェースのどちらを使用するかを決定するために、この記事は非常に役立ちます Source :
私にとってどちらか一方のケースを区別する良い方法は、常に次のとおりです。
「グループ化」して1つで記述できるクラスはたくさんあります名詞?もしそうなら、この名詞の名前で抽象クラスを持ち、そこからクラスを継承します。 (重要な決定者は、これらのクラスが機能を共有し、Animal ...だけをインスタンス化することは決してないことです。常に特定の種類のAnimalをインスタンス化します: 動物基本クラス)例:猫と犬はどちらも抽象クラスから継承できます- 動物、そしてこの抽象基本クラスはメソッドを実装しますvoid Breathe()これにより、すべての動物がまったく同じ方法で実行します。 (このメソッドを仮想化して、ほとんどの動物と同じように呼吸しない魚などの特定の動物に対してオーバーライドできるようにする場合があります)。
どのような種類のverbsをクラスに適用できますか。一般的に他のクラスにも適用できますか?これらの各動詞のインターフェースを作成します。 例:すべての動物に餌を与えることができるので、IFeedableというインターフェイスを作成して、Animalに実装させます。 DogとHorseのみが実装に十分ですILikeable-これは適用されないため、これを基本クラスに実装しません- 猫。
こちらもご覧ください インターフェースvs基本クラス 質問。
抽象クラスを使用する理由の1つは、初期化を強制する必要がある場合です(コンストラクターによる状態など)。
インターフェイスでは、コンストラクタのコントラクトを定義できません。
以下の例では、すべての動物オブジェクトには名前が必要です(SHOULD)。これはインターフェースを介して強制することはできません。
public abstract class Animal
{
public Animal(string name)
{
this.Name = name;
}
public string Name
{
get;
private set;
}
}
public class Cat : Animal
{
public Cat(string name)
: base(name)
{
}
string NoOfLegs { get; set; }
}
class Program
{
static void Main(string[] args)
{
Animal aCat = new Cat("a");
}
}
実際、それらは必ずしも相互に排他的ではありません。コードの実装がどのように進化するかに応じて、両方を使用できます。
インターフェイスは通常、契約の告知です。これは、実装者が敬意を払うべき予想される動作を定義します。そして、通常public apiをinterfacesに対してコーディングすることは良い習慣と考えられています。このようにして、実装の詳細への結合を減らし、コードのリファクタリングとメンテナンスを容易にします。ここでパブリックAPIとして認められるのは、設計で定義された高レベルの相互作用を具体化し、同じプロジェクト内または他の独立したスコープの複数のプロジェクト内で自分自身と他のユーザーが再利用できるようにするソフトウェアコンポーネントです。
A 基本クラスはすでに実装の一部です。インターフェイスを実装するかどうか。また、潜在的な階層を特定の実装の詳細(オブジェクトの状態、オーバーライド可能なメソッドまたはオーバーライド不可能なメソッドなど)に関連付けます。
インターフェースはより柔軟な構成です。基本クラスは1つしか持てませんが、多くのインターフェースを実装できます。オブジェクトが複数の動作をサポートする必要があるが、それらの動作の複数が特定の基本クラスを必要とする場合、そのようにすることはできません。
Danが指摘するように、基本クラスは、基本実装を提供できるという点で、多くの言語で便利です。インターフェースでこれを行うには、基本実装を提供するクラスを作成し、各インターフェースメソッドの実装をそのクラスに手動で委任する必要があります。
ここで類推が役立つと思います:
抽象基本クラス:-自動車メーカーは、いくつかの変形(1.6、2Lなど)があるガソリンエンジンを開発することがあります。エンジンブロックのキャストは抽象的な基本クラスと考えることができます。つまり、エンジンの基本的な形状と機能を定義します。 2Lバージョンでは、シリンダーヘッドなどが大きくなる場合があります。
インターフェース:-エンジンは、さまざまな既成のコンポーネントを使用することもできます。オルタネーター、ラジエーター、スターターモーターなどなので、これらのコンポーネントによって定義されたinterfacesを実装する必要があります。これらのコンポーネントは通常、それらを使用する可能性のあるエンジンの知識なしに設計されました。
必要に応じて、基本的に両方を併用できます。ただし、通常は、継承されたクラスで使用する一部のメソッドまたはプロパティに使用できる基本クラス。基本クラスを作成する場合は、抽象化することをお勧めします。基本クラスで仮想メソッドを使用して継承クラスでオーバーライドし、異なる方法で使用することで、より柔軟になります。
インターフェースを使用すると、より柔軟になります。まず最初に、このインターフェースから継承したクラス間で宣言を行います。これとともに
Interfaces helps to reduce coupling and therefore allow you to easily interchange implementations for the same concept without the underlying code being affected
ユニットテストを簡単に作成できます。
詳細については、こちら this の質問をご覧ください。