実装に関しては、基本タイプまたはインターフェイスをどのように決定する必要がありますか?私はいくつかの例を試してみましたが、完全なアイデアはわかりません:(
方法と理由の例をいただければ幸いです。
基本クラスは、抽象であろうとなかろうと、実装されたメンバーを含むことができます。インターフェイスはできません。すべての実装が同様に実行される場合は、すべての子クラスが基本クラスのメンバーの同じ実装を共有できるため、基本クラスが最適な方法である可能性があります。実装を共有しない場合は、インターフェースが最適な方法かもしれません。
例:
class Person
{
string Name { get; set; }
}
class Employee : Person
{
string Company { get; set; }
}
Name
Employeeクラスは実装を共有しているため、プロパティを定義する必要がないため、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
、基本クラスから継承することは意味がありません。
基本クラスを作成し、に抽象メンバーのみが含まれていることがわかった場合は、インターフェイスを使用することもできます。
また、j__mが示すように、複数の基本クラスから継承することはできませんが、複数のインターフェースを実装することはできます。
私は通常、最初にインターフェイスを定義し、実装でコードを複製していることに気付いた場合は、インターフェイスを実装する基本クラスを作成し、実装にそれを継承させます。
抽象クラスを使用するかインターフェースを使用するかを決定するには、この記事が非常に役立つと思います。出典:
私にとってどちらの場合かを区別する良い方法は、常に次のとおりです。
「グループ化」して1つの名詞で表すことができるクラスはたくさんありますか?もしそうなら、この名詞の名前で抽象クラスを持ち、そこからクラスを継承します。(重要な決定要因は、これらのクラスが機能を共有し、動物だけをインスタンス化することは決してないということです...常に特定の種類の動物をインスタンス化します: Animal基本クラス の実装)例:猫と犬は両方とも抽象から継承できますクラスAnimal、およびこの抽象基本クラスはメソッドvoid Breathe()を実装しますしたがって、すべての動物がまったく同じ方法で行います。(このメソッドを仮想化して、ほとんどの動物と同じように呼吸しないFishなどの特定の動物に対してオーバーライドできるようにする場合があります)。
私のクラスにはどのような動詞を適用できますか?それは一般的に他の人にも適用される可能性がありますか?これらの動詞ごとにインターフェースを作成します。 例:すべての動物に餌を与えることができるので、IFeedableというインターフェイスを作成し、 Animalに実装させます。ILikeableを実装するには、 DogとHorseだけが十分です。これはCatには適用されないため、基本クラスには実装しません。
このインターフェイスと基本クラスの質問もご覧ください。
抽象クラスを使用する理由の1つは、初期化を強制する必要がある場合です(コンストラクターを介した状態など)。
インターフェイスでは、コンストラクターのコントラクトを定義できません。
以下の例では、すべてのAnimalオブジェクトに名前を付ける必要があります。これは、インターフェイスを介して強制することはできません。
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");
}
}
実際、それらは必ずしも相互に排他的ではありません。コード実装がどのように進化するかに応じて、両方を使用できます。
インターフェースは通常、契約の告知です。これは、実装者が尊重すべき期待される動作を定義します。また、通常、パブリックAPIをインターフェースに対してコーディングすることをお勧めします。そうすることで、実装の詳細への結合を減らし、コードのリファクタリングとメンテナンスを容易にすることができます。現在、パブリックAPIと見なされるのは、設計で定義された高レベルの相互作用を具体化するソフトウェアコンポーネントであり、同じプロジェクト内または独立したスコープの複数のプロジェクト内で自分自身と他の人が再利用できるようにすることを目的としています。
基本クラスすでに実装の一部です。インターフェイスを実装するかどうか。また、潜在的な階層を特定の実装の詳細(オブジェクトの状態、オーバーライド可能なメソッドまたはオーバーライド不可能なメソッドなど)に関連付けます。
インターフェイスはより柔軟な構成です。基本クラスは1つしか持てませんが、多くのインターフェースを実装できます。複数のビヘイビアーをサポートするオブジェクトが必要であるが、それらのビヘイビアーの複数が特定の基本クラスを必要とする場合、それはできません。
Danが指摘しているように、基本クラスには、基本実装を提供できるという点で、多くの言語で便利な利点があります。インターフェイスでこれを行うには、基本実装を提供するクラスを作成してから、各インターフェイスメソッドの実装をそのクラスに手動で委任する必要があります。これはそれほど便利ではありません。
私はここで類推が役立つと思います:
抽象基本クラス:- 自動車メーカーは、いくつかのバリエーション(1.6、2Lなど)を持つガソリンエンジンを開発する場合があります。エンジンブロックの鋳造は、抽象的な基本クラスと見なすことができます。つまり、エンジンの基本的な形状と機能を定義します。2Lバージョンはより大きなシリンダーヘッドなどを持っているかもしれません。
インターフェース:- エンジンは、オルタネーター、ラジエーター、スターターモーターなどのさまざまな既製のコンポーネントも使用する可能性があるため、これらのコンポーネントによって定義されたインターフェースを実装する必要があります。これらのコンポーネントは通常、それらを使用する可能性のあるエンジンの知識がなくても設計されました。
基本的に、必要に応じて両方を一緒に使用できます。ただし、一般的に、継承されたクラスでも使用するいくつかのメソッドまたはプロパティに使用できる基本クラス。基本クラスを作成する場合は、抽象化する方が適切です。基本クラスで仮想メソッドを使用して、継承されたクラスで仮想メソッドをオーバーライドし、異なる方法で使用することで、より柔軟になります。
インターフェイスを使用すると、より柔軟になります。まず最初に、このインターフェースから継承したクラス間で宣言を行います。これとともに
コードを読みやすくします
インターフェイスAから継承されたクラスはMssqlデータベースに接続できますが、別のクラスはMysqlデータベースに接続できるように、概念を分離します。
yorコードはより保守しやすくなります。Interfaces helps to reduce coupling and therefore allow you to easily interchange implementations for the same concept without the underlying code being affected
依存性注入を使用できます
ユニットテストを簡単に作成できます。
詳細については、こちらの質問をご覧ください。