抽象クラスの代わりにインターフェースを使用する場合、およびその逆の場合


427

これは一般的なOOPの質問である可能性があります。使用法に基づいて、インターフェースと抽象クラスの一般的な比較を行いたかったのです。

いつインターフェースを使いたいのか、いつ抽象クラスを使いたいのか?


1
これは多くの質問を受けてきました:stackoverflow.com/questions/56867/interface-vs-base-class
mmcdole 2009年

1
この下の解答への追加では、インターフェイスを好むしたい場合がありますどこの素敵な短いリストがあり、どこがない場合がありますときにするために使用されたインタフェース:msdn.microsoft.com/en-us/library/3b5b8ezk(v=vs.80) .aspx
アンソニー、

クラスが何をするかを確信できない場合は、abstractを使用してください。もしそうなら、インターフェイスを使用してください。
UğurGümüşhan

マイクロソフトで働いていない開発者が日々の開発でインターフェイスを定義して使用している開発者の数を知りたいです。
user1451111 2018

回答:


432

私はそれについての記事を書きました:

抽象クラスとインターフェース

要約:

抽象クラスについて話すときは、オブジェクト型の特性を定義しています。オブジェクトとは何かを指定します

インターフェースについて話し、提供することを約束する機能を定義するとき、それはオブジェクトが何ができるかについてのコントラクトを確立することについて話している。


114
これは非常に役に立ちましたInterfaces do not express something like "a Doberman is a type of dog and every dog can walk" but more like "this thing can walk"。ありがとう
aexl

2
リンクが機能していないようです。
KimAhlstrømMeyn Mathiassen 2015年

下記のアレックスの説明は、re:実装された関数のみを記述した場合と格納された状態を記述した場合の違いは、哲学的な違いだけではないため、この質問に対するより良い回答のように見えます。
Duncan Malashock 2016年

1
ダンカンマラショック ホルヘの答えはより良いものです。アレックスの答えは力学に焦点を当てていますが、ホルヘは意味論に重点を置いています。
Nazar Merza 2016年

8
私はあなたの指定された答えの前の声明が好きです:Use abstract classes and inheritance if you can make the statement “A is a B”. Use interfaces if you can make the statement “A is capable of [doing] as”
S1r-Lanzelot

433

抽象クラスは、状態または機能を共有できます。インターフェイスは、状態または機能を提供するための約束にすぎません。優れた抽象クラスは、その機能または状態を共有できるため、書き換えが必要なコードの量を削減します。インターフェースには、共有する定義済みの情報がありません


65
これは、私にとって、ここでの最良の答えです。はい、2つの概念には哲学的な違いがありますが、根本的なポイントは、抽象クラスがすべての子孫が機能/状態を共有することを保証し、インターフェースが共通の結合のみを保証することです。
drharris

3
たとえば、テンプレートメソッドのデザインパターンには抽象基本クラスが使用され、戦略のデザインパターンにはインターフェイスが使用されます。
Raedwald 2014

1
ホルヘの要約は、両方の存在の背後にあるものの主要なものを説明していると思いますが、アレックスの答えは結果の違いです。両方を正しい答えとしてマークしたいのですが、それでもホルヘの答えを好みます。
Chirantan 2014

そして、ここにあるのコードと。
shaijut

私にとって、「優れた抽象クラスは、その機能や状態を共有できるため、書き換えが必要なコードの量を削減します。」ステートメントは答えの中核です。
divティワリ

82

個人的には、抽象クラスを書く必要はほとんどありません。

ほとんどの場合、抽象クラスが(誤)使用されているのを目にしています。これは、抽象クラスの作成者が「テンプレートメソッド」パターンを使用しているためです。

「テンプレートメソッド」の問題は、ほぼ常に再入可能であることです。「派生」クラスは、実装している基本クラスの「抽象」メソッドだけでなく、基本クラスのパブリックメソッドも認識します、ほとんどの場合それを呼び出す必要はありませんが。

(過度に簡略化された)例:

abstract class QuickSorter
{
    public void Sort(object[] items)
    {
        // implementation code that somewhere along the way calls:
        bool less = compare(x,y);
        // ... more implementation code
    }
    abstract bool compare(object lhs, object rhs);
}

したがって、ここでは、このクラスの作成者が一般的なアルゴリズムを記述しており、人々が独自の「フック」(この場合は「比較」メソッド)を提供することで「特殊化」して使用することを意図しています。

したがって、意図された使用法は次のようなものです:

class NameSorter : QuickSorter
{
    public bool compare(object lhs, object rhs)
    {
        // etc.
    }
}

これの問題は、次の2つの概念を過度に結合していることです。

  1. 2つのアイテムを比較する方法(どのアイテムを最初に実行する必要があるか)
  2. アイテムをソートする方法(つまり、クイックソートとマージソートなど)

上記のコードでは、理論的には、「compare」メソッドの作成者は、スーパークラスの「Sort」メソッドに再入可能にコールバックできます。

この不要なカップリングに支払う代償として、スーパークラスを変更するのは難しく、ほとんどのOO言語では実行時に変更することはできません。

代わりの方法は、代わりに "Strategy"デザインパターンを使用することです:

interface IComparator
{
    bool compare(object lhs, object rhs);
}

class QuickSorter
{
    private readonly IComparator comparator;
    public QuickSorter(IComparator comparator)
    {
        this.comparator = comparator;
    }

    public void Sort(object[] items)
    {
        // usual code but call comparator.Compare();
    }
}

class NameComparator : IComparator
{
    bool compare(object lhs, object rhs)
    {
        // same code as before;
    }
}

だから今気づいてください:私たちが持っているのはインターフェースとそれらのインターフェースの具体的な実装だけです 実際には、高レベルのOO設計を行うために他に何も必要ありません。

「QuickSort」クラスと「NameComparator」を使用して「名前の並べ替え」を実装したという事実を「非表示」にするために、どこかにファクトリメソッドを作成する場合があります。

ISorter CreateNameSorter()
{
    return new QuickSorter(new NameComparator());
}

抽象クラスを持っているときはいつでもこれを行うことができます...基本クラスと派生クラスの間に自然な再入可能な関係がある場合でも、通常はそれらを明示的にすることでお金がかかります。

最後に1つ考えてみましょう。関数型プログラミング言語では、「QuickSort」関数と「NameComparison」関数を使用して「NameSorting」関数を「構成」するだけで、このスタイルのプログラミングがさらに自然になります。少ないコードで。


5
抽象クラスまたはテンプレートメソッドパターンを使用できるからといって、それらを回避する必要があるわけではありません。ストラテジーパターンは、この例のように、状況によって異なるパターンですが、テンプレートパターンがストラテジーよりもはるかに適している例はたくさんあります。
ホルヘコルドバ

5
まあ、私の経験では、決してそれらに遭遇することはありません(テンプレートメソッドが推奨される状況)...またはほとんどとにかく そして、それがすべて「抽象的」です-「テンプレートメソッド」デザインパターンの言語サポート。
ポールホリングスワース

わかりました。プロセスが次のようなエキスパートシステムで1回使用しました。1を取得します。2。FillTheParameters、2。その間にベクトル積を作成します。3。各ペアの計算結果について、4。ステップ1と3の結果を結合します委任され、2と4は基本クラスで実装されます。
ホルヘコルドバ、

10
抽象クラスの使用はほとんどすべて理解するのが難しいと思います。継承関係の代わりに相互に通信するボックスの観点から考えると(私にとっては)簡単です...しかし、現在のOO言語では定型文が多すぎることにも同意します...関数型はOOを通過する方法になります
Paul Hollingsworth

4
誤用の例はかなり簡単です。それは、比較のような素晴らしい機能を取り除いたものになることはめったにありません。より一般的なのは、派生クラスが置換または拡張するデフォルト機能がいくつかある状況です(後者の場合、基本クラスの関数を呼び出すことは完全に有効です)。あなたの例ではデフォルトの機能がないので、抽象クラスの使用は正当化されません。
SomeWittyUsername 2015年

41

JavaをOOP言語として見ている場合、

インターフェースはメソッド実装を提供しません」は、Java 8の起動では無効になりました。現在、Javaはデフォルトのメソッドのインターフェースに実装を提供しています。

簡単に言えば、使用したいと思います

インターフェース:複数の無関係なオブジェクトによるコントラクトを実装します。「 HAS A」機能を提供します。

抽象クラス:複数の関連オブジェクト間で同じまたは異なる動作を実装するため。「 IS A」関係を確立します。

OracleのWebサイトには、interfaceabstractクラスの主な違いがあります。

次の場合は、抽象クラスの使用を検討してください

  1. 密接に関連するいくつかのクラス間でコードを共有したい。
  2. 抽象クラスを拡張するクラスには、多くの一般的なメソッドやフィールドがあるか、パブリック以外のアクセス修飾子(保護されたものやプライベートなものなど)が必要です。
  3. 非静的フィールドまたは非最終フィールドを宣言したい。

次の場合は、インターフェースの使用を検討してください

  1. 無関係なクラスがインターフェースを実装することを期待しています。たとえば、多くの無関係なオブジェクトがSerializableインターフェイスを実装できます。
  2. 特定のデータ型の動作を指定したいが、その動作を誰が実装するかは気にしない。
  3. タイプの多重継承を利用したい。

例:

抽象クラス(IS A関係)

Readerは抽象クラスです。

BufferedReaderReader

FileReaderReader

FileReaderおよびBufferedReader共通の目的で使用されます:データの読み取り、およびそれらはReaderクラスを通じて関連付けられます。

インターフェイス(HAS A機能)

Serializableはインターフェースです。

アプリケーションに2つのクラスがあり、Serializableインターフェースを実装していると仮定します。

Employee implements Serializable

Game implements Serializable

ここでは、経由どんな関係を確立することはできませんSerializableとの間のインターフェイスEmployeeGame異なる目的のために意図されています、。どちらも状態をシリアル化でき、比較はそこで終了します。

これらの投稿をご覧ください。

インターフェイスと抽象クラスの違いをどのように説明すればよいですか?


40

OK、これを自分で「グロッキー」にしたところ-これは素人の言葉です(私が間違っている場合は自由に修正してください)-私はこのトピックが間違っていることを知っていますが、誰かがいつかつまずくかもしれません...

抽象クラスを使用すると、設計図を作成したり、子孫すべてに所有させたいプロパティとメソッドを追加で構築(実装)したりできます。

一方、インターフェイスでは、特定の名前のプロパティやメソッドが、それを実装するすべてのクラスに存在することを宣言できるだけですが、実装方法は指定しません。また、クラスは多くのインターフェイスを実装できますが、拡張できる抽象クラスは1つだけです。インターフェースは、より高レベルのアーキテクチャツールです(デザインパターンを把握し始めると、より明確になります)。アブストラクトは両方の陣営に足を踏み入れ、汚れた作業の一部を実行することもできます。

なぜどちらを使うのか?前者は子孫のより具体的な定義を可能にし、後者はより大きな多形性を可能にします。この最後のポイントは、エンドユーザー/コーダーにとって重要です。エンドユーザー/コーダーは、この情報を利用して、ニーズに合わせてさまざまな組み合わせ/形状でAP I(インターフェース)を実装できます。

これは私にとって「電球」の瞬間だったと思います。インターフェースについては、著者の視点からではなく、プロジェクトに実装を追加したり、APIを拡張したりするチェーンの後半に登場するコーダーの視点から考えてください。


これに基づいて構築する:インターフェイスを実装するオブジェクトは、そのTYPEを引き受けます。これは非常に重要です。したがって、インターフェイスのさまざまなバリエーションをクラスに渡すことができますが、インターフェイスのタイプ名を使用してそれら(およびそれらのメソッド)を参照できます。したがって、スイッチまたはif / elseループの必要がなくなります。このチュートリアルをテーマで試してください-ストラテジーパターンを介したインターフェースの使用方法を示しています。 phpfreaks.com/tutorial/design-patterns---strategy-and-bridge/...
sunwukung

私はあなたの電球の瞬間について完全に同意します:「彼らのニーズに合うようにさまざまな組み合わせ/形状のAPI(インターフェース)」!作成するのに非常に非常に良い点。
Trevor Boyd Smith、

39

私の2セント:

インターフェイスは基本的にコントラクトを定義します。これは、実装クラスが遵守する必要がある(インターフェイスメンバーの実装)コントラクトです。コードは含まれていません。

一方、抽象クラスにはコードを含めることができ、継承クラスが実装する必要がある抽象としてマークされたメソッドがいくつかある場合があります。

私が抽象クラスを使用したまれな状況は、いくつかの特殊なクラスが継承する抽象基底クラスなど、継承するクラスがオーバーライドすることに興味がないかもしれないデフォルト機能がある場合です。

例(非常に初歩的な一つが!):のような抽象メソッドを持っている顧客と呼ばれる基本クラスで考えてみましょうCalculatePayment()CalculateRewardPoints()とのようないくつかの非抽象メソッドをGetName()SavePaymentDetails()

RegularCustomer およびなどの特殊化されたクラスGoldCustomerは、Customer基本クラスから継承し、独自のメソッドCalculatePayment()CalculateRewardPoints()メソッドロジックを実装しますが、GetName()およびSavePaymentDetails()メソッドを再利用します。

古いバージョンを使用していた子クラスに影響を与えることなく、抽象クラス(つまり、非抽象メソッド)に機能を追加できます。一方、インターフェースにメソッドを追加すると、新しく追加されたインターフェースメンバーを実装する必要があるため、インターフェースを実装するすべてのクラスに影響します。

すべての抽象メンバーを持つ抽象クラスは、インターフェースに似ています。


1
+1「古いバージョンを使用していた子クラスに影響を与えずに、抽象クラス(つまり非抽象メソッド)に機能を追加できます。インターフェイスにメソッドを追加すると、実装する必要があるため、インターフェイスを実装するすべてのクラスに影響します。新しく追加されたインターフェイスメンバー。」
divティワリ

インターフェースは「デフォルト」のメソッドを持つことができるので、インターフェースにメソッドを実装しないことは間違った考えです。「親子」IS-A関係がここでの鍵です。また、「共有属性」対「共有プロパティ」。例:犬iS-A動物。しかし、犬は「歩く」こともできます
ha9u63ar

30

あなたが心の中に明確な概念を持っているなら、非常に単純なことで何をすべきか。

抽象クラスは派生できますが、インターフェースは実装できます。2つの間にいくつかの違いがあります。抽象クラスを派生させると、派生クラスと基本クラスの関係は「is a」関係になります。たとえば、犬は動物、羊は動物です。これは、派生クラスが基本クラスからいくつかのプロパティを継承していることを意味します。

インターフェースの実装では、関係は「できる」です。たとえば、犬はスパイ犬になることができます。犬はサーカス犬になることができます。犬は競走犬になることができます。つまり、何かを取得するための特定のメソッドを実装します。

私は明確であることを望みます。


11

1.無関係なクラスに共通の機能を提供するものを作成する場合は、インターフェースを使用します。

2.階層内で密接に関連しているオブジェクトに対して何かを作成する場合は、抽象クラスを使用します。


10

抽象クラスをいつ使用し、いつインターフェースを使用するかについての記事を書きました。それらの間には、「1つのIS-A ...と1つのCAN-DO ...」以外に多くの違いがあります。私にとって、これらは定型の答えです。どちらを使用するかについて、いくつかの理由を述べます。それが役に立てば幸い。

http://codeofdoom.com/wordpress/2009/02/12/learn-this-when-to-use-an-abstract-class-and-an-interface/


7

私はそれを置く最も簡単な方法は次のとおりだと思います:

共有プロパティ=>抽象クラス。
共有機能=>インターフェース。

簡潔に言うと...

抽象クラスの例:

public abstract class BaseAnimal
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }
}

public class Dog : BaseAnimal
{
    public Dog() : base(4) { }
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }
}

動物には共有プロパティ(この場合は脚の数)があるため、この共有プロパティを含む抽象クラスを作成することは理にかなっています。これにより、そのプロパティを操作する一般的なコードを作成することもできます。例えば:

public static int CountAllLegs(List<BaseAnimal> animals)
{
    int legCount = 0;
    foreach (BaseAnimal animal in animals)
    {
        legCount += animal.NumberOfLegs;
    }
    return legCount;
}

インターフェースの例:

public interface IMakeSound
{
    void MakeSound();
}

public class Car : IMakeSound
{
    public void MakeSound() => Console.WriteLine("Vroom!");
}

public class Vuvuzela : IMakeSound
{
    public void MakeSound() => Console.WriteLine("VZZZZZZZZZZZZZ!");        
}

ここで、ブブゼラと車は完全に異なるものですが、機能を共有しています。したがって、ここではインターフェースが理にかなっています。さらに、プログラマーは、共通のインターフェースの下で音を出すものをグループ化することができます- IMakeSoundこの場合。この設計では、次のコードを記述できます。

List<IMakeSound> soundMakers = new List<ImakeSound>();
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Vuvuzela());

foreach (IMakeSound soundMaker in soundMakers)
{
    soundMaker.MakeSound();
}

それが何を出力するかわかりますか?

最後に、2つを組み合わせることができます。

組み合わせ例:

public interface IMakeSound
{
    void MakeSound();
}

public abstract class BaseAnimal : IMakeSound
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }

    public abstract void MakeSound();
}

public class Cat : BaseAnimal
{
    public Cat() : base(4) { }

    public override void MakeSound() => Console.WriteLine("Meow!");
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }

    public override void MakeSound() => Console.WriteLine("Hello, world!");
}

ここでは、すべてBaseAnimalのが音を出すことを要求していますが、その実装はまだわかりません。このような場合、インターフェースの実装を抽象化して、その実装をサブクラスに委任できます。

最後に、抽象クラスの例では、さまざまなオブジェクトの共有プロパティを操作でき、インターフェイスの例では、さまざまなオブジェクトの共有機能を呼び出すことができたことを思い出してください。この最後の例では、両方を行うことができます。


7

インターフェイスよりも抽象クラスを好む場合は?

  1. プログラム/プロジェクトの存続期間を通じて基本クラスの更新を計画している場合は、基本クラスを抽象クラスにすることを許可するのが最善です。
  2. 階層で密接に関連しているオブジェクトのバックボーンを構築しようとしている場合、抽象クラスを使用することは非常に有益です

抽象クラスよりもインターフェースを好む場合は?

  1. 大規模な階層型のフレームワークを扱っていない場合は、インターフェースが最適です
  2. 抽象クラスでは多重継承がサポートされていないため(ダイヤモンドの問題)、インターフェイスで時間を節約できます

10年近く前の質問に22番目の答えが必要だと思ったのはなぜですか。
jonrsharpe

3
質問に対する単純な答えを探すようになったのと同じタイプの考え方。
サティア

1
FWIW、私はこの答えが大好きです。
ブレントリッテンハウス

6

クラスは1つの基本クラスからのみ継承できるため、抽象クラスを使用してクラスのグループにポリモーフィズムを提供する場合は、それらすべてがそのクラスから継承する必要があります。抽象クラスは、すでに実装されているメンバーを提供する場合もあります。したがって、抽象クラスを使用して一定量の同一の機能を保証できますが、インターフェースを使用して保証することはできません。

コンポーネントにポリモーフィズムを提供するためにインターフェイスまたは抽象クラスのどちらを使用するかを決定するのに役立ついくつかの推奨事項を次に示します。

  • コンポーネントの複数のバージョンを作成する予定がある場合は、抽象クラスを作成します。抽象クラスは、コンポーネントをバージョン管理するためのシンプルで簡単な方法を提供します。基本クラスを更新することにより、すべての継承クラスが変更に応じて自動的に更新されます。一方、インターフェイスは、この方法で作成された後は変更できません。新しいバージョンのインターフェースが必要な場合は、まったく新しいインターフェースを作成する必要があります。
  • 作成している機能がさまざまな異種オブジェクト全体で役立つ場合は、インターフェースを使用します。抽象クラスは主に密接に関連するオブジェクトに使用する必要がありますが、インターフェースは関連のないクラスに共通の機能を提供するのに最適です。
  • 小さく簡潔な機能を設計する場合は、インターフェースを使用してください。大規模な機能ユニットを設計する場合は、抽象クラスを使用します。
  • コンポーネントのすべての実装に共通の実装機能を提供する場合は、抽象クラスを使用します。抽象クラスではクラスを部分的に実装できますが、インターフェースにはメンバーの実装が含まれていません。

コピー元:http :
//msdn.microsoft.com/en-us/library/scsyfw1d%28v=vs.71%29.aspx


UMLには、複数のクラスの継承を妨げるものはありません。多重継承は、UMLではなくプログラミング言語によって決定されます。たとえば、複数のクラスの継承はJavaとC#では許可されていませんが、C ++では許可されています。
BobRodes、2015年

@BobRodes:オブジェクト指向フレームワークがさまざまな組み合わせで提供できる多くの機能がありますが、すべての組み合わせではありません。一般化された多重継承は、実際のインスタンスの親タイプまたはそれによってサポートされるインターフェースタイプに参照を直接キャストする機能、基本タイプと派生タイプを個別にコンパイルして実行時にそれらを結合する機能など、他のいくつかの便利な機能の組み合わせを排除します。
スーパーキャット2016

@supercat Yoursは、多重継承を使用した結果生じるいくつかの問題の良い説明です。それにもかかわらず、UMLには、ダイアグラムで複数のクラスの継承を妨げるものはありません。上記の「クラスは1つの基本クラスからのみ継承する可能性があります...」に対応していましたが、そうではありません。
BobRodes

@BobRodes:質問のタグはJavaでした。Javaには示された機能が含まれているため、「致命的なひし形」を生成できない複数の継承の形式に制限されます(実際、デフォルトのインターフェース実装を実装した方法では、ひどいひし形が可能になります)。
スーパーキャット2016

@supercatああ、わかりました。私は通常、Javaタグを見ていないので、少なくとも、UMLの回答についてコメントしていると思っていたと書いていました。いずれにせよ、私はあなたのコメントに同意します。
BobRodes 2016

3

これらのステートメントのいずれかが状況に当てはまる場合は、抽象クラスの使用を検討してください。

  1. 密接に関連するいくつかのクラス間でコードを共有したい。
  2. 抽象クラスを拡張するクラスには、多くの一般的なメソッドまたはフィールドがあるか、パブリック以外のアクセス修飾子(保護されたものやプライベートなものなど)が必要です。
  3. 非静的フィールドまたは非最終フィールドを宣言したい。これにより、属しているオブジェクトの状態にアクセスして変更できるメソッドを定義できます。

これらのステートメントのいずれかが状況に当てはまる場合は、インターフェースの使用を検討してください。

  1. 無関係なクラスがインターフェースを実装することを期待しています。たとえば、インターフェースComparableおよびCloneableは、多くの無関係なクラスによって実装されます。
  2. 特定のデータ型の動作を指定したいが、その動作を誰が実装するかは関係ありません。
  3. 複数の継承を利用したい。

ソース


2

答えは言語によって異なります。たとえば、Javaでは、クラスは複数のインターフェースを実装(継承)できますが、継承する抽象クラスは1つだけです。したがって、インターフェースにより柔軟性が高まります。しかし、これはC ++では当てはまりません。


2

私にとっては、多くの場合、インターフェースを使用します。しかし、私はいくつかのケースで抽象クラスを好む。

オブジェクト指向のクラスは、一般的に実装を指します。実装の詳細を子に強制したい場合は、抽象クラスを使用します。それ以外の場合は、インターフェースを使用します。

もちろん、抽象クラスは、実装を強制するだけでなく、多くの関連クラス間で特定の詳細を共有するのにも役立ちます。


1

基本的な実装を提供する場合は、抽象クラスを使用します。


1
セバスチャンに感謝します。しかし、基本的な実装が必要ない場合はどうなりますか?抽象クラスとインターフェースは、これがそれらの間の唯一の違いである場合、同じではありませんか?なぜ違いがあるのですか?
Chirantan 2009年

1
一部の言語にはインターフェースがないため-C ++。
jmucchiello 2009年

1

Javaでは、1つの(抽象的な)クラスから継承して機能を「提供」し、多くのインターフェースを実装して機能を「保証」できます。


lil 'ヒント:抽象クラスとインターフェースから継承したい場合は、抽象クラスがインターフェースを実装していることを確認してください
Andreas Niedermair

1

純粋に継承に基づいて、子孫の抽象関係(すなわち、animal-> cat)を明確に定義している抽象を使用するか、仮想または非パブリックプロパティ、特に共有状態(インターフェイスがサポートできない)の継承を必要とします。 )。

ただし、可能な場合は、継承よりも(依存性注入を介して)構成を優先し、インターフェイスはコントラクトであるため、抽象化ではできない方法で、ユニットテスト、問題の分離、および(言語によって異なる)多重継承をサポートすることに注意してください。


1

インターフェースが抽象クラスよりもうまく機能する興味深い場所の1つは、(関連するまたは関連しない)オブジェクトのグループに機能を追加する必要がある場合です。それらに基本抽象クラスを与えることができない場合(たとえば、それらはsealed親であるか、すでに親を持っている)、代わりにダミー(空)インターフェースを与えて、そのインターフェースの拡張メソッドを記述するだけです。


0

これは非常に難しい電話です...

1つのポインタ:オブジェクトは多くのインターフェイスを実装できますが、オブジェクトは1つの基本クラスしか継承できません(c#のような最近のOO言語では、C ++には複数の継承があることはわかっていますが、それは不快ではありませんか?)


多重継承により、Mixinをシームレスに実装できます。よく書かれたMixinは扱いが簡単ですが、手に入れるのは非常に難しく、どこかに不足することなく書くのは困難です。ミックスインはIMOですが全体としてはかなりクールです。
Martijn Laarman、2009年

実際私はそうしませんでした。多重継承は確かに私たちオタクの間の確かな議論の火花です。実際、私はあなたの答えに賛成票を投じました。
Martijn Laarman、2009年

私が試みた唯一の点は、単一継承の言語でMixinする方法も可能である(C#、PHP、JavaScript)が、ハックな動作またはタックな構文を使用することです。Mixinは機能するときは大好きですが、多重継承を行うかどうかはまだ決まっていません。
Martijn Laarman、2009年

この答えは、設計上の違いというよりは構文上の違いです。彼はデザインの違いを求めていると思います
Pramod Setlur 2015

0

抽象クラスは実装を持つことができます。

インターフェイスには実装がなく、一種のコントラクトを定義するだけです。

また、言語に依存するいくつかの違いがある可能性があります。たとえば、C#には複数の継承はありませんが、複数のインターフェイスをクラスに実装できます。


「一種の契約」と言うと、ウェブサービスのようなものですか?
Chirantan 2009年

技術的には、Webサービスはインターフェースでは機能しません。コントラクトとは、オブジェクトのユーザーがそのオブジェクトに存在するメソッドを知っていることを意味します。たとえば、インターフェースIMouseにはMoveメソッドと、左および右のマウスボタンイベントがあります。
Gerrie Schenck、

-1

基本的な経験則は次のとおりです。 「名詞」にはAbstractクラスを使用し、「動詞」にはインターフェースを使用します。

例:carは抽象クラスでありdrive、インターフェースにすることができます。


5
これは意味がありませんdrive。車内にの機能を配置することもできます。これは抽象クラスです。
アルスランアリ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.