質問
共通の機能のために基本クラスから継承する複数のクラスがある場合、クラスまたは抽象クラスを使用して基本クラスを実装する必要がありますか?
解決
それは依存します。基底クラスをインスタンス化したくない場合は、抽象化します。それ以外の場合は、通常のクラスのままにします。
他のヒント
基本クラスをインスタンス化する必要がない場合は抽象クラスにします-基本クラスをインスタンス化する必要がある場合は抽象化しません。
この例では、基本クラスには具体的な意味がないため、基本クラスを抽象化することは理にかなっています。
abstract class WritingImplement
{
public abstract void Write();
}
class Pencil : WritingImplement
{
public override void Write() { }
}
ただし、この次の例では、基本クラスに具体的な意味があることを確認できます。
class Dog
{
public virtual void Bark() { }
}
class GoldenRetriever : Dog
{
public override void Bark() { }
}
これはすべてかなり主観的なものです。特定のドメインのニーズに基づいて、かなり良い判断を下せるはずです。
依存しますが、問題の基本クラスが派生せずに独自に存在することは理にかなっていますか?答えが「はい」の場合、通常のクラスである必要があり、そうでない場合、抽象クラスである必要があります。
提案:
- インターフェースを作成します。
- 基本クラスにインターフェースを実装します。
- 基本クラスを抽象クラスではなく実際のクラスにします(理由については以下を参照)。
抽象クラスではなく実際のクラスを好む理由は、抽象クラスをインスタンス化できないため、将来のオプションが不必要に 制限されるためです。たとえば、後で基本クラスによって提供される状態とメソッドが必要になる場合がありますが、インターフェイスを継承する必要はなく、実装する必要もありません。基本クラスが抽象の場合は運が悪いですが、基本クラスが通常のクラスの場合は、基本クラスのインスタンスを作成し、それを他のクラスのコンポーネントとして保持し、インスタンスに委任して再利用できます提供される状態/メソッド。
はい、これは頻繁に起こりませんが、ポイントは、基本クラスを抽象化することで、そうする理由がない限り、この種の再利用/解決策を防ぐことです。
今、ベースクラスをインスタンス化することが何らかの形で危険である場合、それを抽象化します-または、できれば危険を軽減します;-)
銀行口座のように考えてください:
「アカウント」と呼ばれる一般的な抽象的な基本アカウントを作成できます。これには、顧客の詳細などの基本情報が保持されます。
「SavingAccount」という2つの派生クラスを作成できます。または" DebitAccount"基本クラスの動作の恩恵を受けながら、独自の特定の動作を持つことができます。
これは、顧客が普通預金口座または借方口座、一般的な「口座」、説明がないだけのアカウントを持つことは現実の世界ではあまり一般的ではないため、許可されません。
必要に応じて同様のシナリオを作成できる場合は、抽象が最適です。
抽象クラスは、部分的に実装されたクラス用です。
それ自体では、抽象クラスのインスタンスを持つことは意味をなさないため、派生させる必要があります。基本クラスを作成できるようにする場合は、抽象クラスにすることはできません。
抽象クラスは、すべてのサブクラスに共通であるため、いくつかのメンバーが事前に定義されているインターフェースと考えています。
これを別の方法で考えてください
基本クラスはそれ自体が完全なオブジェクトですか?
答えが「いいえ」の場合、抽象化します。はいの場合、おそらく具体的なクラスにしたいでしょう。
基本クラスを単独で呼び出す予定がない場合は、抽象クラスとして定義する必要があります。
基本クラスを単独で実装するかどうかによって異なります。
抽象クラスとして、そこからオブジェクトを作成することはできません。
抽象クラスは、事前定義された機能に最適です。たとえば、クラスが公開すべき最小限の正確な動作は知っているが、クラスやその実装に使用するデータはわかりません。
abstract class ADataAccess
{
abstract public void Save();
}
通常の(非抽象)クラスは、同様のものには最適ですが、それらを作成するには実装の詳細を知っている必要があります。
public class DataAccess
{
public void Save()
{
if ( _is_new )
{
Insert();
}
else if ( _is_modified )
{
Update();
}
}
}
また、インターフェースを(個別に、または抽象であるかどうかにかかわらずクラスで)使用して、同じ種類のプロトタイプ定義を定義できます。
interface ISaveable
{
void Save();
void Insert();
void Update();
}
class UserAccount : ISavable
{
void ISavable.Save() { ... }
void ISavable.Insert() { ... }
void ISavable.Update() { ... }
}
さらに別のオプションはジェネリックを使用している可能性があります
class GenDataAccess<T>
{
public void Save()
{
...
}
}
これらのメソッドはすべて、使用するクラスの特定のプロトタイプを定義するために使用できます。コードAがコードBと通信できることを確認する方法。もちろん、上記のすべてを好みに合わせて組み合わせることができます。明確な正しい方法はありませんが、インターフェイスと抽象クラスを定義し、インターフェイスを参照するのが好きです。この方法により、「配管」に関する思考要件の一部がなくなります。最大限の柔軟性を維持しながら、より高いレベルのクラスで。 (インターフェースを持つことで、抽象基本クラスを使用する要件はなくなりますが、オプションとして残します。)
多くの皆さんは、基本的なオブジェクト指向クラスを再度登録する必要があると思います。
OOA / OODの基本的な基本原則は、抽象化できなくなるまで抽象抽象化することです。あなたが見ているものが抽象化であるなら、そうである、それはあなたのOOA / OODがすでにあなたに言ったことです。ただし、「コード」かどうか疑問にそこに座っている場合抽象的であるか、そうでない場合は、用語の意味が明らかにわからないので、基本的なOOA / OOD / OOPをもう一度学んでください:-)
さらに、設計パターンと調和理論を学ぶ必要があります。これは、オブジェクト指向設計を非常に助けます!