インターフェイスと抽象クラス(一般的なOO)


1413

最近、電話インタビューを2回行ったところ、インターフェースと抽象クラスの違いについて尋ねられました。私は考えられるすべての側面について説明しましたが、彼らは私が特定のことを述べるのを待っているようで、それが何であるかわかりません。

私の経験から、次のことが正しいと思います。重要な点が足りない場合はお知らせください。

インターフェース:

インターフェースで宣言されたすべてのメソッドは、サブクラスで実装する必要があります。インターフェイスに存在できるのは、イベント、デリゲート、プロパティ(C#)、およびメソッドのみです。クラスは複数のインターフェースを実装できます。

抽象クラス:

サブクラスでは、抽象メソッドのみを実装する必要があります。Abstractクラスは、実装を伴う通常のメソッドを持つことができます。抽象クラスは、イベント、デリゲート、プロパティ、メソッドの横にクラス変数を持つこともできます。C#にはマルチ継承が存在しないため、クラスは1つの抽象クラスしか実装できません。

  1. 結局のところ、インタビュアーは「抽象メソッドのみを持つ抽象クラスがあるとしたらどうでしょうか?それはインターフェースとどう違うのですか?」私は答えを知りませんでしたが、それは上記のように継承だと思いますか?

  2. 別のインタビュアーから、インターフェイス内にパブリック変数がある場合、抽象クラスとどう違うのかと尋ねられました。インターフェイス内にパブリック変数を含めることはできないと私は主張しました。私は彼が何を聞きたいのか知りませんでしたが、彼も満足していませんでした。

以下も参照してください


412
両者の違いを知ることは重要だと思いますが、これはインタビューの良い質問ではありません、imo。仕事がオブジェクト指向のトピックに関する本を書いているのでなければ。あのコウモリのために働いていないほうがいいです。
アラン

107
@アラン:私は実際にこれをインタビューの質問として気に入っていますが、このように誰かに引っ掛けるつもりはありません-おそらく、「階層を定義するときに、抽象基本クラス上のインターフェイスをどこで選択しますか? "、または同様の何か。
リードコプシー

11
多分彼らはよりデザインに焦点を当てた答えを求めていたのかもしれません...あなたのように私はそれを技術的な質問として扱っただろう。
CurtainDog 2010年

16
ここに表の素敵な違いがあります:mindprod.com/jgloss/interfacevsabstract.html
Rajat_R

30
@ケーブ:I insisted you can't have a public variable inside an interface.私はインターフェイスがパブリック変数を持つことができると思います。実際、インターフェースの変数は自動的に公開され、最終的なものになります。
2013

回答:


746

あなたの質問はそれが「一般的なオブジェクト指向」のためのものであることを示していますが、それは本当にこれらの用語の.NETの使用に焦点を合わせているようです。

.NET(Javaと同様)の場合:

  • インターフェースに状態や実装を含めることはできません
  • インターフェイスを実装するクラスは、そのインターフェイスのすべてのメソッドの実装を提供する必要があります
  • 抽象クラスには、状態(データメンバー)や実装(メソッド)を含めることができます。
  • 抽象クラスは、抽象メソッドを実装せずに継承できます(そのような派生クラス自体は抽象です)
  • インターフェースは多重継承されている可能性がありますが、抽象クラスはそうではない可能性があります(これが、インターフェースが抽象クラスとは別に存在する主な具体的な理由です-一般的なMIの問題の多くを取り除く多重継承の実装を許可します)。

一般的なオブジェクト指向用語として、違いは必ずしも明確に定義されていません。たとえば、同様の厳密な定義を保持するC ++プログラマーがいます(インターフェイスは、実装を含めることができない抽象クラスの厳密なサブセットです)一方で、一部のデフォルト実装を持つ抽象クラスはまだインターフェイスである、または非抽象的であると言う人もいますクラスはまだインターフェースを定義できます。

実際、非仮想インターフェース(NVI)と呼ばれるC ++のイディオムがあり、パブリックメソッドは、プライベート仮想メソッドに「サンク」する非仮想メソッドです。


7
ありがとうございました。私はあなたの答えが状態+すべての残りの良い概要を述べているので、私はあなたの応答を最終的な答えとしてマークします。最初のインタビュアーが一般オブジェクト指向を要求したので、私は一般オブジェクト指向を求めましたが、私はC#の人なので、それを忘れがちです。;-) C ++の説明にも感謝します。
ホウマン、

6
Michaelが提供した説明の要点は、インターフェイスを実装するときは、インターフェイスのすべてのメンバーを実装する必要があるということですが、抽象クラスから継承する場合、子クラスが親のメンバーを実装する必要はありません
Guillermo Gomez

82
+1:他の言語がオブジェクト指向を異なるように実装していることを他の言語が認識していないことを、インタビューをホストしているそれらのサルが気付かないことを私は喜んで賭けます。
オービットのライトネスレース2012年

2
@JL問題がどこにあるのかわかりません。抽象メソッドと抽象クラスを混同しているようです。抽象メソッドには実装がありません。ただし、抽象クラスの内部では、一部のメソッドは抽象(つまり、実装なし)にすることができ、一部のメソッドは実際に実装することができます。
xji 2014

19
Java 8では、インターフェースにデフォルトのメソッドと静的メソッドを含めることができるようになりました。つまり、Javaインターフェースに実装を含めることができます。参照はこちら。明らかにあなたは主に.NETを参照していたので、これはJavaを参照した単なる観察結果です。
davtom 2014

867

アナロジーについてはどうですか。私が空軍にいたとき、私はパイロットトレーニングに行き、USAF(米国空軍)パイロットになりました。その時点では、私は何も飛行する資格がなく、航空機タイプの訓練に参加する必要がありました。資格を得ると、私はパイロット(抽象クラ​​ス)とC-141パイロット(コンクリートクラス)になりました。私の割り当ての1つで、私は追加の任務を与えられました:安全管理者。今でも私はパイロットとC-141パイロットでしたが、私は安全担当官の職務も行いました(いわばISafetyOfficerを実装しました)。パイロットは安全担当官である必要はありませんでした、他の人もそれをすることができたでしょう。

USAFパイロットはすべて、特定の空軍全体の規制に従う必要があり、すべてのC-141(またはF-16、またはT-38)パイロットはUSAFパイロットです。誰でも安全担当官になることができます。したがって、要約すると:

  • パイロット:抽象クラス
  • C-141パイロット:具象クラス
  • ISafety Officer:インターフェース

追加注記:これは、概念を説明するための類推であり、コーディングの推奨で​​はありませんでした。以下のさまざまなコメントを参照してください。ディスカッションは興味深いものです。


87
私はこのアナロジーが本当に好きです。少し複雑なトピックを説明するために簡単な例を使用しています
Kevin Bowersox 2012年

13
これは、複雑なオブジェクト指向の用語を理解するための最良の方法です。要するに、すべての理論は、それを実際に利用できる場合にのみ価値があります。@Jay、あなたが例を挙げれば、いくつかの箇条書きのポイントを把握するのは本当に簡単です(吸収されるのではなく、主に貫通する心です!)
vs

54
私はまだ少し混乱しています。たとえば、F-16とT-38の資格を取得したため、クラスJayが複数のクラス(C-141パイロット、F-16パイロット、T-38パイロット)から継承できない場合、そのクラスがインターフェイスになる必要があるということですか?ありがとう
Alex Okrushko

37
この例の弱点が明らかになるため、多くの人がアレックスのコメントに+1を正しく与えています。最初に、ジェイはそれ自身のクラスではなくC-141Pilotのインスタンスであると言います。さらに、USAFではすべてのパイロットの99%が一度に1つの航空機でのみ認定されているため(FCFとテストパイロットは注目すべき例外です)、複数の認定とその実装方法については考慮していません。50年前に25機の航空機で同時に資格を取得したパイロットを知っているので、多重継承を使用したくない例を示していると思います。
ジェイ

20
1人のパイロットが一度に複数の飛行機を操縦することはまずないので、戦略パターンを実装する良い機会です。パイロットは認定のコレクションを持ち、実行時に正しいものを選択します。認証は、TakeOff、Land、Ejectメソッドを使用して、IFlyPlaneインターフェイスを実装する動作としてコード化されます。
Michael Blackburn

221

彼らが求めている答えは、根本的またはOPPSの哲学的違いだと思います。

抽象クラスの継承は、派生クラスが抽象クラスのコアプロパティと動作を共有する場合に使用されます。実際にクラスを定義する動作の種類。

一方、クラス継承が必ずしも派生クラスを定義しないペリフェラル動作を共有する場合は、インターフェイス継承が使用されます。

たとえば 車とトラックは、Automobile抽象クラスの多くのコアプロパティと動作を共有しますが、DrillersやPowerGeneratorsなどの非自動車クラスでさえ共有し、必ずしも車やトラックを定義するわけではない、Generate排気のようないくつかの周辺動作を共有します、したがって、Car、Truck、Driller、PowerGeneratorはすべて同じインターフェースIExhaustを共有できます。


32
さらに良いアナロジーは、インターフェイスのコントラクトの性質を示す「usesFuel」でしょう。
ピュアフェレット2012

@Pureferret accelerateがAutomobile抽象クラスのコア動作の一部である場合accelerate契約の性質を示しているとは言えません。契約の性質とは何ですか?なぜcontract私たちが話すたびにこの言葉が導入されたのinterfaceですか?
オーバーエクスチェンジ、2014

@overexchangeは、通常、インターフェイスは2つの「表面」が出会う場所にすぎませんが、契約という言葉は、2つの「表面」が出会う方法が一致していることを意味します。少なくとも私にとっては、排気ガスを発生させることが「同意する」ものであることは意味がありません。しかし、私にとっても、Fuelを使用する必要があることに同意できることは理にかなっています。
Pureferret 2014年

1
@Pureferret私はでクエリを上げたリンクと同じのため
overexchange

1
@Pureferret interfaceが周辺動作を必要とする場合、なぜpublic interface List<E> extends Collection<E> {}がコア動作を記述するように設計されているのlistですか?これは実際にはプラスンの答えと矛盾しています。両方ともここCollection<E>List<E>はインターフェースです。
14年

198

Short:抽象クラスは、類似したクラスのクラス階層のモデリングに使用されます(たとえば、Animalは抽象クラス、Human、Lion、Tigerは具体的な派生クラスにすることができます)

そして

インターフェースは、インターフェースを実装するクラスのタイプを考慮しない2つの類似/非類似クラス間の通信に使用されます(たとえば、高さはインターフェースプロパティであり、ヒューマン、ビルディング、ツリーによって実装できます。食べることができるかどうかは問題ではありません。 、泳いだり、死んだりすることができます。高さ(クラスでの実装)が必要なことだけが重要です)。


7
構造だけではなく、構造ではなく、意図などの抽象的なものを見ると、物事の「何が違うのか」に答えることが難しい場合があるため、この答えが本当に好きです(構造的には、インターフェースと純粋な抽象クラスはほとんど同じです)事)。
LostSalad 2014

抽象クラス対インターフェイスが特定の言語で何ができるかを列挙するのは簡単ですが、オブジェクトに意味と責任を与える抽象化を作成すること、およびオブジェクト指向の2つの概念の使用を完全に再開することの方が難しいです。ありがとう!
サミュエル

2
@dhananjay:どうやってHeightをAnimalクラスの概念から分離し、別のクラスから分離できるかがわかりますが、クラス間の「通信」とはどういう意味ですか?それは単に自分のクラスのHeightを定義しているだけですよね?
TTT

77

他にもいくつかの違いがあります-

インターフェースに具体的な実装を含めることはできません。抽象基本クラスはできます。これにより、そこで具体的な実装を提供できます。これにより、抽象基本クラスが実際により厳密なコントラクトを提供できるようになりますが、インターフェイスは実際にはクラスの使用方法のみを記述します。(抽象基本クラスには、動作を定義する非仮想メンバーを含めることができます。これにより、基本クラスの作成者により多くの制御が与えられます。)

クラスには複数のインターフェースを実装できます。クラスは、単一の抽象基本クラスからのみ派生できます。これにより、インターフェースを使用した多態的な階層が可能になりますが、抽象基本クラスは使用できません。これにより、インターフェースを使用した疑似マルチ継承も可能になります。

抽象基本クラスは、APIを壊すことなくv2 +で変更できます。インターフェースへの変更は重大な変更です。

[C#/。NET固有]インターフェイスは、抽象基本クラスとは異なり、値型(構造体)に適用できます。構造体は抽象基本クラスから継承できません。これにより、行動契約/使用ガイドラインを値タイプに適用できます。


5
+1は、クラスに複数のインターフェースを実装できるという重要なポイントです。
cgp 2009

これが、抽象基本クラスであるIMOよりもインターフェイスの優れた点の1つです。それ以外の場合、私は.NET設計ガイドラインに同意します。これは、「インターフェイスよりも抽象基本クラスを優先する」とあります
リードコプシー

ただし、インターフェイスを任意のクラスに適用できるという点も追加できれば非常に気になります。
cgp 2009

1
@altCognito:それは、第2段落で処理されたようなものだと考えました。ただし、これはインターフェイスが値型で機能することを思い出させたので、それを追加しました。
リードコプシー

この正確な説明をありがとうございました。それは確かに非常に役立ちます。私はここでは新人です。2つの回答を「回答」として選択できないのは残念です。私を混乱させる1つのことは、抽象 'base'クラスの使用法です。すべての抽象クラスは、サブクラスの基本クラスになることを意図しています。なぜ「ベース」エクストラに名前を付けるのですか?
ホウマン、

68

継承
車とバスを考えてみましょう。彼らは2つの異なる車両です。しかし、それでも、ステアリング、ブレーキ、ギア、エンジンなどのように、いくつかの共通のプロパティを共有しています。
したがって、継承の概念では、これは次のように表すことができます...

public class Vehicle {
    private Driver driver;
    private Seat[] seatArray; //In java and most of the Object Oriented Programming(OOP) languages, square brackets are used to denote arrays(Collections).
    //You can define as many properties as you want here ...
}

今自転車...

public class Bicycle extends Vehicle {
    //You define properties which are unique to bicycles here ...
    private Pedal pedal;
}

そして車...

public class Car extends Vehicle {
    private Engine engine;
    private Door[] doors;
}

これが継承のすべてです。上記で見たように、これらを使用してオブジェクトをより単純なBaseフォームとその子に分類します。

抽象クラス

抽象クラスは不完全なオブジェクトです。さらに理解するために、車両のアナロジーをもう一度考えてみましょう。
車両を運転することができます。正しい?しかし、さまざまな車両がさまざまな方法で運転されます...たとえば、自転車を運転するように車を運転することはできません。
それでは、車両の駆動機能をどのように表すのでしょうか?車両の種類を確認して独自の機能で運転することは困難です。新しいタイプの車両を追加するときは、Driverクラスを何度も変更する必要があります。
抽象クラスとメソッドの役割がここに来ます。継承するすべての子がこの関数を実装する必要があることを伝えるために、driveメソッドを抽象として定義できます。
したがって、車両クラスを変更すると...

//......Code of Vehicle Class
abstract public void drive();
//.....Code continues

自転車と車はまた、それを運転する方法を指定する必要があります。そうしないと、コードはコンパイルされず、エラーがスローされます。
つまり、抽象クラスは一部の不完全なクラスであり、いくつかの不完全な関数があり、継承する子はそれを指定する必要があります。

インターフェース インターフェースは完全に不完全です。プロパティはありません。彼らは単に、継承する子供たちが何かを
することができることを示します... あなたがあなたと一緒に異なるタイプの携帯電話を持っていると仮定します。それぞれに異なる機能を実行するための異なる方法があります。例:人を呼び出す。電話のメーカーはそれを行う方法を指定します。ここで、携帯電話は番号をダイヤルできます-つまり、ダイヤル可能です。これをインターフェースとして表現しましょう。

public interface Dialable {
    public void dial(Number n);
}

ここで、Dialableのメーカーは、番号をダイヤルする方法を定義します。ダイヤルする番号を指定するだけです。

// Makers define how exactly dialable work inside.

Dialable PHONE1 = new Dialable() {
    public void dial(Number n) {
        //Do the phone1's own way to dial a number
    }
}

Dialable PHONE2 = new Dialable() {
    public void dial(Number n) {
        //Do the phone2's own way to dial a number
    }
}


//Suppose there is a function written by someone else, which expects a Dialable
......
public static void main(String[] args) {
    Dialable myDialable = SomeLibrary.PHONE1;
    SomeOtherLibrary.doSomethingUsingADialable(myDialable);
}
.....

これにより、抽象クラスの代わりにインターフェースを使用することで、Dialableを使用する関数の作成者は、そのプロパティについて心配する必要がありません。例:タッチスクリーンまたはダイヤルパッドはありますか、固定電話または携帯電話ですか。それがダイヤル可能かどうかを知る必要があるだけです。Dialableインターフェイスを継承(または実装)しますか?

そしてもっと重要なことは、いつかあなたが別のものとDialableを切り替えるなら

......
public static void main(String[] args) {
    Dialable myDialable = SomeLibrary.PHONE2; // <-- changed from PHONE1 to PHONE2
    SomeOtherLibrary.doSomethingUsingADialable(myDialable);
}
.....

ダイヤラブルを使用する関数は、ダイヤラブルインターフェイスで指定された詳細以外の詳細に依存しない(およびできない)ため、コードが完全に機能することを確認できます。どちらもDialableインターフェースを実装しており、それが関数が気にする唯一のものです。

インターフェースは、共通の機能を共有する限り(オブジェクトを固定電話や携帯電話に変更する場合と同じように、番号をダイヤルする必要がある限り)、オブジェクト間の相互運用性(互換的に使用)を保証するために開発者によって一般的に使用されます。つまり、インターフェイスは、プロパティのない抽象クラスのはるかに単純なバージョンです。
また、必要な数のインターフェイスを実装(継承)できますが、拡張(継承)できるのは単一の親クラスのみです。

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


「インターフェースにプロパティがない」というのは本当ではありません。
Bigeyes 2017年

@ Bigeyes、javaはインターフェースのプロパティを許可しません。他の言語でも同じだと思いました。詳しく説明していただけますか?
fz_salam 2017年

私はC#/。Netを参照しています。例を
Bigeyes 2017年

インターフェイスがプロパティを持つことができるC#の@Bigeyesは、多重継承の問題を再導入しませんか?クラスが同じプロパティを定義した複数のインターフェースを使用するとどうなりますか?好奇心旺盛な感謝
stackPusher

@happycoder:re:「ここでは、抽象クラスの代わりにインターフェースを使用することで、そのプロパティについて心配する必要はありません。例:タッチスクリーンやダイヤルパッドはありますか、固定電話か携帯電話ですか。それがダイヤル可能であるかどうかを確認します。それは、ダイヤル可能インターフェースを継承(または実装)しますか?」-これをコード例で示してもらえますか、それがどのように継承されるかわかりませんでした...
TTT

45

javaこの質問に答えるのにOOP言語と見なすと、Java 8リリースでは上記の回答の内容の一部が廃止されます。これで、Javaインターフェースは、具体的な実装を備えたデフォルトのメソッドを持つことができます。

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

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

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

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

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

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

インターフェース:複数の無関係なオブジェクトによるコントラクトを実装する

抽象クラス:複数の関連オブジェクト間で同じまたは異なる動作を実装する

明確な方法で物事を理解するためにコード例を見てください:インターフェイスと抽象クラスの違いをどのように説明すべきですか?


33

インタビュアーは奇妙な木を吠えています。C#やJavaなどの言語では違いがありますが、C ++などの他の言語では違いがありません。OO理論は2つを区別せず、単に言語の構文を区別します。

抽象クラスは、継承される継承と実装(純粋仮想メソッド)の両方を備えたクラスです。インターフェイスには通常、実装はなく、純粋な仮想関数のみがあります。

C#またはJavaでは、実装のない抽象クラスは、継承から使用される構文のみがインターフェイスと異なり、継承できるのはインターフェイスからのみであるという事実です。


1週間前に同じ質問を受けました。Javaの経験はありませんが、しばらくの間C ++を使用しています。インタビュアーは質問をする前に言語を指定しなかったので、この場合のインターフェースは状態や種類の実装のない抽象クラスであることを説明しました。私も奇妙な質問だと思います。
dacabdi 2017

31

インターフェースを実装することで、継承( "is-a"関係)ではなく構成( "has-a"関係)を実現します。継承ではなく動作の構成を実現するためにインターフェイスを使用する必要があるデザインパターンなどに関しては、これは重要な原則です。


17
インターフェースは、IMOより「Acts-as-a」関係を実現します。カプセル化は、インターフェイスよりも優れた構成を実現します。
リードコプシー

12
実装するインターフェースが構成に入るとは思わない。
Pavan Dittakavi

さらに、IDisposableのように、インターフェイスが「機能」を記述するために使用する可能性が高くなります。これらのクラスが何かを「実行できる」という機能をクラス間で共有するために使用されていました。IFlyableの他の例は、鳥と飛行機で実装できます。しかし、鳥はエアクラフトからエアクラフトが派生するクラスクリーチャーから派生するかもしれません。
Peter.Wang

26

インターフェイスと抽象クラスの深さの詳細について説明します。インターフェイスと抽象クラスの概要を知っている場合、インターフェイスを使用する場合と抽象クラスを使用する場合の最初の質問が思い浮かびます。以下のインターフェースと抽象クラスの説明を確認してください。

  1. いつインターフェイスを使用する必要がありますか?

    実装について知らない場合は、要件の仕様があるだけで、インターフェイスを使用します

  2. いつ抽象クラスを使うべきですか?

    実装はわかっているが完全には理解していない場合(部分的に実装)、抽象クラスを使用します。

    インターフェース

    デフォルトでは、すべてのメソッドがパブリック抽象であるということは、インターフェースが100%純粋な抽象であることを意味します。

    概要

    抽象クラスに実装を持つ具象メソッドとは、具象メソッドと抽象メソッドを持つことができます。抽象クラスは、抽象として宣言されたクラスであり、抽象メソッドを含む場合と含まない場合があります。

    インターフェース

    インターフェイスをプライベートで保護されたものとして宣言することはできません

    Q.インターフェイスを非公開および保護として宣言しないのはなぜですか?

    デフォルトでは、インターフェースメソッドはパブリック抽象なので、そのため、インターフェースをプライベートで保護されていると宣言していないからです。

    インターフェイスメソッド
    も、プライベート、保護、最終、静的、同期、ネイティブとしてインターフェイスを宣言できません。

    私は理由を説明します:インターフェイスのオブジェクトを作成して同期することができないので同期メソッドを宣言していない理由はオブジェクトに対して機能するので、同期メソッドを宣言していない息子の理由Transientの概念も適用されません。

    概要

    public、private final static ....と一緒に楽しく使用しています。つまり、抽象的に適用される制限はありません。

    インターフェース

    変数はデフォルトでpublic static finalとしてInterfaceで宣言されているので、変数はプライベートで保護されたものとして宣言されていません。

    揮発性修飾子もインターフェイスには適用されません。インターフェイス変数はデフォルトでpublic static finalおよびfinal変数であるため、値を変数に割り当てた後は値を変更できず、変数をインターフェイスに宣言した後は変数を割り当てる必要があります。

    そして、揮発性変数は変更を維持するため、oppです。最後に、インターフェースで揮発性変数を使用しない理由です。

    概要

    抽象変数はpublic static finalを宣言する必要はありません。

この記事がお役に立てば幸いです。


4
この点に同意しAbstract class must have at lease one abstract method.ません。実装する限り、AbstractメソッドなしでAbstractクラスを作成することは可能です。参照:An abstract class is a class that is declared abstract—it may or may not include abstract methods.参照ソース:docs.oracle.com/javase/tutorial/java/IandI/abstract.html
Devner

あなたは技術的な詳細と実装について話しているのですが、一般的なOOPに関する質問には答えていません
Billal Begueradj

26

概念的に言えば、言語固有の実装、ルール、利点を維持し、誰かまたは両方を使用してプログラミング目標を達成することは、コード/データ/プロパティ、何とか何とか、単一または複数の継承をすべて持つことができるかできないか

1-抽象(または純粋な抽象)クラスは、階層を実装するためのものです。ビジネスオブジェクトが構造的に似ていて、親子(階層)の種類の関係を表している場合にのみ、継承/抽象クラスが使用されます。ビジネスモデルに階層がない場合は、継承を使用しないでください(ここではプログラミングロジックについて話していません。たとえば、一部のデザインパターンには継承が必要です)。概念的には、抽象クラスはOOPでビジネスモデルの階層を実装する方法であり、インターフェイスとは何の関係もありません。抽象クラスをインターフェイスと実際に比較しても、どちらも概念的にまったく異なるため、意味がありません。インタビューでは、概念を確認するためだけに尋ねられます。実装に関してはどちらも多少同じ機能を提供しているように見え、プログラマーは通常コーディングをより重視しているためです。[抽象化は抽象クラスとは異なることも覚えておいてください]。

2-インターフェースは契約であり、1つ以上の機能セットで表される完全なビジネス機能です。それが実装され、継承されない理由です。ビジネスオブジェクト(階層の一部であるかどうかにかかわらず)は、完全なビジネス機能をいくつでも持つことができます。抽象クラスとは何の関係もないということは、一般的に継承を意味します。たとえば、人間はRUN、象はRUN、鳥はRUNなどのように、異なる階層のこれらすべてのオブジェクトは、RUNインターフェースまたはEATまたはSPEAKインターフェースを実装します。これらのインターフェースを実装するタイプごとに抽象クラスを持つものとして実装する可能性があるため、実装は行わないでください。階層のオブジェクトは、その階層とは何の関係もない機能(インターフェース)を持つことができます。

私は、インターフェイスは多重継承を実現したり、パブリック動作を公開したりするために発明されたのではないと考えています親のコア構造(プロパティ+機能)を持つ子を生成する階層の親

違いについて尋ねられた場合、明示的に尋ねられない限り、それは言語固有の実装の違いではなく、実際には概念的な違いです。

両方のインタビュアーは、これら2つの間の1行の直接的な違いを期待していたと思います。

抽象メソッドのみを持つ抽象クラスがある場合はどうなりますか?


それはこの質問への答えをかなりよく要約しています。
プラナバン

実装された機能と拡張された構造、いいですね!
harshvchawla

21

.Netの場合

2番目のインタビュアーへの答えは1番目のインタビュアーへの答えでもあります...抽象クラスには実装があり、状態を持つことができ、インターフェースはできません...

編集:別のメモでは、インターフェイスを「実装するように定義されている」クラスを説明するために「サブクラス」(または「継承」フレーズ)というフレーズを使用することすらしません。私にとって、インターフェースは、そのインターフェースを「実装する」ように定義されている場合にクラスが準拠しなければならないコントラクトの定義です。何も継承しません...明示的にすべてを自分で追加する必要があります。


2
はい!状態!それが、2番目のインタビュアーがインターフェース内で「パブリック変数」と言う彼の奇妙な方法で意味したことです。やった!抽象クラスは状態を持つことができますが、インターフェースは持つことができません!そして、そうです、私は言及するのを忘れていましたが、後ですでに理解している継承の方法の違いにも同意します。:) みんな、ありがとう!
ホウマン、

4
状態だけではありません...抽象クラスは実装を持つことができます。つまり、実際に実行されて基本クラスのインスタンスによって継承および実行されるコードを含むメソッドを持つことができます...インターフェイスではそうではありません
Charles Bretana

それ以上に、ある意味では、抽象クラスをインスタンス化できます。直接ではなく、派生クラス定義を使用してインスタンス化する必要があります。ただし、抽象クラスで定義された状態変数は、派生クラスのインスタンスを新しく作成することによって作成されたオブジェクトでインスタンス化されます。このインスタンスは、抽象クラスのインスタンスであり、派生クラスのインスタンスでもあります-結局のところ、それから派生したものです。これは、インターフェースには当てはまりません。
Charles Bretana

インターフェースを実装するために定義されたクラスのインスタンスを新しくする場合、それはそのインターフェースの「インスタンス」ではありません。すべての構文により、コンパイラーはクラスのコードを調べ、すべての動作(メソッド、プロパティ、イベント、イベントハンドラーなど)は、インターフェースによって定義され、クラスのコードに実装されています。
Charles Bretana

20

インターフェース:相互に関連するかどうかに関係なく、コンポーネントのルールを暗示する場合に使用する必要があります

長所:

  1. 多重継承が可能
  2. コンテキストで使用されているオブジェクトの正確な種類を公開しないことにより、抽象化を提供します
  3. 契約の特定の署名によって一貫性を提供します

短所:

  1. 定義されたすべての契約を実装する必要があります
  2. 変数またはデリゲートを持つことはできません
  3. 一度定義すると、すべてのクラスを壊さなければ変更できません

抽象クラス:相互に関連するコンポーネントの基本的またはデフォルトの動作または実装が必要な場合に使用する必要があります

長所:

  1. インターフェースよりも高速
  2. 実装に柔軟性があります(完全または部分的に実装できます)
  3. 派生クラスを壊すことなく簡単に変更できます

短所:

  1. インスタンス化できません
  2. 多重継承をサポートしていません

より速く定義します。それは重要ですか?それはどういう意味ですか?抽象クラスでの関数呼び出しのオペコードは、インターフェイスでの関数呼び出しのオペコードよりも高速ですか?
denis631

@ denis631抽象クラスは、インターフェイスメソッド内で検索と呼び出しが行われるため、インターフェイスよりもわずかに高速です。このコードを
bouraxウェブマスター

17

デザインではなく技術的な違いがあったので、彼らはあなたの反応を嫌っていたと思います。質問は私にとっては荒らしの質問のようです。実際、インターフェースと抽象クラスはまったく異なる性質を持っているため、実際にそれらを比較することはできません。インターフェイスの役割と抽象クラスの役割についての私のビジョンを説明します。

インターフェース:契約を確実にし、クラス間の結合を低くして、より保守可能でスケーラブルでテスト可能なアプリケーションを実現するために使用されます。

抽象クラス:同じ責任のクラス間で一部のコードを因数分解するためにのみ使用されます。これは、クラスが多くの責任を処理すべきではないため(代わりに構成を使用するため)、OOPで多重継承が悪いことである主な理由であることに注意してください。

したがって、インターフェイスは実際のアーキテクチャ上の役割を果たしますが、抽象クラスは実装の詳細にすぎません(もちろん、正しく使用した場合)。


13
After all that, the interviewer came up with the question "What if you had an 
Abstract class with only abstract methods? How would that be different
from an interface?" 

ドキュメントは、抽象クラスに抽象メソッド宣言のみが含まれる場合は、代わりにインターフェースとして宣言する必要があることを明確に述べています。

An another interviewer asked me what if you had a Public variable inside
the interface, how would that be different than in Abstract Class?

インターフェイスの変数は、デフォルトではpublic staticおよびfinalです。抽象クラスのすべての変数がパブリックである場合、質問はどのようにフレーム化できますか?まあ、インターフェイスの変数とは異なり、それらはまだ静的でも非最終でもかまいません。

最後に、上記のポイントにもう1つポイントを追加します。抽象クラスは依然としてクラスであり、単一の継承ツリーに分類されますが、インターフェイスは複数の継承に存在できます。


13
  1. インターフェース:
    • メソッドの実装(または定義)は行わず、派生クラスで行います。
    • インターフェースではメンバー変数を宣言しません。
    • インターフェースはHAS-A関係を表します。つまり、それらはオブジェクトのマスクです。
  2. 抽象クラス:
    • 抽象クラスでメソッドを宣言して定義できます。
    • そのコンストラクタを非表示にします。つまり、そこから直接作成されたオブジェクトはありません。
    • 抽象クラスはメンバー変数を保持できます。
    • 派生クラスは抽象クラスに継承されます。つまり、派生クラスのオブジェクトはマスクされず、抽象クラスに継承されます。この場合の関係はIS-Aです。

これは私の意見。


12

Jeffrey RichterによってC#経由でCLRからコピー...

「基本型とインターフェイスのどちらを設計するべきか」という質問をよく耳にします。答えは必ずしも明確ではありません。

ここにあなたを助けるかもしれないいくつかのガイドラインがあります:

■■IS-AとCAN-DOの関係タイプは1つの実装のみを継承できます。派生型が基本型とのIS-A関係を要求できない場合は、基本型を使用しないでください。インターフェイスを使用します。インターフェイスは、CAN-DO関係を意味します。CAN-DO機能がさまざまなオブジェクトタイプに属しているように見える場合は、インターフェースを使用します。たとえば、型はそれ自体のインスタンスを別の型(IConvertible)に変換でき、型はそれ自体のインスタンスをシリアル化できます(ISerializable)など。値型はSystem.ValueTypeから派生する必要があるため、派生できないことに注意してください。任意の基本クラスから。この場合、CAN-DO関係を使用してインターフェースを定義する必要があります。

■■使いやすさ一般に、インターフェイスのすべてのメソッドを実装するよりも、開発者がベースタイプから派生した新しいタイプを定義する方が簡単です。基本型は多くの機能を提供できるので、派生型はおそらくその動作に比較的小さな変更のみを必要とします。インターフェースを提供する場合、新しいタイプはすべてのメンバーを実装する必要があります。

■■一貫した実装インターフェースコントラクトがどれほど適切に文書化されていても、誰もが100%正しくコントラクトを実装することはほとんどありません。実際、COMにはこの問題があるため、一部のCOMオブジェクトはMicrosoft WordまたはWindows Internet Explorerでのみ正しく機能します。基本型に適切なデフォルト実装を提供することで、機能し、十分にテストされた型の使用を開始します。その後、修正が必要なパーツを修正できます。

■■バージョン管理基本型にメソッドを追加すると、派生型は新しいメソッドを継承し、機能する型を使用して開始するため、ユーザーのソースコードを再コンパイルする必要すらありません。インターフェイスに新しいメンバーを追加すると、インターフェイスの継承者がソースコードを変更して再コンパイルする必要があります。


1
@AbdullahShoaibは、誰でもできることはできますが、できないことです。ここには違いがあります。これが基本的な理由です。インターフェースが必要です。can-do動作abstract classも含まれます。
2014年

10

インターフェイスは、サービスまたはサービスセットのコントラクトを定義します。2つの完全に関連のないクラスが同じインターフェースを実装できるが、両方のクラスがインターフェースによって定義された一連のサービスを満たすことを約束しているため、これらは水平方向に多態性を提供します。インターフェイスは実装の詳細を提供しません。

抽象クラスは、そのサブクラスの基本構造と、オプションで部分的な実装を定義します。抽象クラスは、抽象クラスを継承するすべてのクラスをその抽象クラスのインスタンスとして扱うことができ、その逆はできないという点で、垂直方向ではあるが方向性をもって多態性を提供します。抽象クラスには実装の詳細を含めることができますが、実際にそれをインスタンス化することはできません。サブクラスのみを「更新」できます。

C#では、インターフェイスの継承も可能です。


1
水平および垂直という用語を使用すると、違いを想像することが非常に明確になりました。
インフィニティ

10

ほとんどの回答は、抽象クラスとインターフェイスの技術的な違いに焦点を当てていますが、技術的には、インターフェイスは基本的に一種の抽象クラス(データや実装がないもの)なので、概念の違いははるかに興味深いと思います。面接官は後です。

アン・インターフェースは、ある合意。「これは、私たちが互いに話し合う方法です」と明記しています。いないので、それはどのような実装を持つことができないはずの任意の実装を持っています。それは契約です。.hCのヘッダーファイルのようなものです。

アン抽象クラスである不完全な実装。クラスはインターフェースを実装する場合と実装しない場合があり、抽象クラスはそれを完全に実装する必要はありません。実装のない抽象クラスは役に立たないですが、完全に合法です。

基本的に、抽象かどうかに関係なく、クラスはそれ何であるかに関するものですが、インターフェイスはそれをどのように使用するかについてです。たとえば、Animalいくつかの基本的な代謝機能を実装し、実装を行わずに呼吸と歩行の抽象的なメソッドを指定する抽象クラスである可能性があります。エラや肺を介して呼吸する必要があるかどうか、また、飛ぶ、泳ぐ、歩く、または飛ぶクロール。Mount一方、インターフェースである可能性があります。これは、動物の種類(または動物であるかどうか)を知らなくても、動物に乗ることができることを指定します。

舞台裏では、インターフェースは基本的に抽象メソッドのみを持つ抽象クラスであることは重要ではありません。概念的には、それらはまったく異なる役割を果たします。


10

あなたが専門家からの理論的な知識を持っているかもしれませんが、私はここにすべてのそれらを繰り返すことで多くの言葉を費やしておりません、むしろ私は、我々が使用することはできません/使用することができます簡単な例で説明しましょうInterfaceAbstract class

Carsのすべての機能をリストするアプリケーションを設計しているとしましょう。DigitalFuelMeter、エアコン、シート調整などの一部のプロパティはすべての車に共通しているため、さまざまな点で共通の継承が必要です。同様に、ブレーキシステム(ABS、EBD)などの一部のプロパティは一部の車にのみ適用できるため、一部のクラスの継承のみが必要です。

以下のクラスは、すべての車の基本クラスとして機能します。

public class Cars
{
    public string DigitalFuelMeter()
    {
        return "I have DigitalFuelMeter";
    }

    public string AirCondition()
    {
        return "I have AC";
    }

    public string SeatAdjust()
    {
        return "I can Adjust seat";
    }
}

車ごとに個別のクラスがあると考えてください。

public class Alto : Cars
{
    // Have all the features of Car class    
}

public class Verna : Cars
{
    // Have all the features of Car class + Car need to inherit ABS as the Braking technology feature which is not in Cars        
}

public class Cruze : Cars
{
    // Have all the features of Car class + Car need to inherit EBD as the Braking technology feature which is not in Cars        
}

VernaとCruzeのブレーキ技術を継承する方法が必要だと考えてください(Altoには適用されません)。どちらもブレーキ技術を使用していますが、「技術」は異なります。したがって、メソッドが抽象として宣言され、その子クラスに実装される抽象クラスを作成しています。

public abstract class Brake
{
    public abstract string GetBrakeTechnology();
}

ここで、この抽象クラスから継承しようとしています。ブレーキシステムのタイプは、VernaとCruzeで実装されています。

public class Verna : Cars,Brake
{
    public override string GetBrakeTechnology()
    {
        return "I use ABS system for braking";
    }       
}

public class Cruze : Cars,Brake
{
    public override string GetBrakeTechnology()
    {
       return "I use EBD system for braking";
    }         
}

上記の2つのクラスの問題を参照してください。それらは、メソッドが子に実装されていても、C#.Netが許可しない複数のクラスから継承します。ここでインターフェイスの必要性が出てきます。

interface IBrakeTechnology
{
    string GetBrakeTechnology();
}

そして、実装は以下のとおりです。

public class Verna : Cars, IBrakeTechnology
{
    public string GetBrakeTechnology()
    {
        return "I use ABS system for braking";
    }
}

public class Cruze : Cars, IBrakeTechnology
{
   public string GetBrakeTechnology()
   {
       return "I use EBD system for braking";
   }        
}

今では、VernaとCruzeは、Interfaceの助けを借りて、独自の種類のブレーキングテクノロジーで多重継承を実現できます。


4
これは例のため、最も良い説明の1つです。
アダムメンドーサ

2
これは頭​​を悩ませることなく私には理にかなっています。私は生徒のために車の例を考え出そうとしていました。これをまとめる時間を与えてくれてありがとう。
tazboy 2017年

9

インターフェイスは、特定の動作を強制する軽量な方法です。それは考えるべき1つの方法です。


8

これらの回答はすべて長すぎます。

  • インターフェイスは動作を定義するためのものです。

  • 抽象クラスは、振る舞いを含め、モノ自体を定義するためのものです。そのため、インターフェイスを継承するいくつかの追加プロパティを持つ抽象クラスを作成することがあります。

これは、Javaがクラスの単一継承のみをサポートし、インターフェースに制限を設けない理由も説明します。具体的なオブジェクトは異なるものにすることはできませんが、異なる動作をすることができるためです。


7

1)インターフェースは純粋な抽象クラスと見なすことができますが、同じですが、それにもかかわらず、インターフェースの実装と抽象クラスからの継承は異なります。この純粋な抽象クラスから継承する場合、階層->継承を定義します。インターフェイスを実装しない場合は、実装せず、必要な数のインターフェイスを実装できますが、継承できるのは1つのクラスのみです。

2)インターフェイスでプロパティを定義できるため、そのインターフェイスを実装するクラスにはそのプロパティが必要です。

例えば:

  public interface IVariable
  {
      string name {get; set;}
  }

そのインターフェイスを実装するクラスには、そのようなプロパティが必要です。


7

この質問はかなり古いですが、インターフェースを支持してもう1つポイントを追加したいと思います。

インターフェースは、Dependency Injectionツールを使用して注入できますが、Abstractクラスの注入はほとんどサポートされていません。


1
私はあなたがDIツールがインターフェースを実装するクラスを注入できることを意味すると信じています。そのようなツールの中には、抽象クラスから派生したクラスを挿入するものもありますが、それは不可能ですか?
John Saunders、

6

私の別の答えから、主に一方を他方に対して使用するタイミングを扱います:

私の経験では、同じメソッドに応答する必要があるクラスがいくつかあり、それらのクラスの共通のインターフェイスに対して作成される他のコードでそれらを交換可能に使用できる場合に、インターフェイスが最もよく使用されます。インターフェイスが最もよく使用されるのは、プロトコルが重要な場合ですが、基礎となるロジックはクラスごとに異なる場合があります。ロジックを複製する場合は、代わりに抽象クラスまたは標準クラスの継承を検討してください。


6

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

Pro C#5.0と.NET 4.5 Frameworkブックから改作。

インターフェイスタイプは、抽象基本クラスに非常に似ているように見える場合があります。クラスが抽象としてマークされている場合、クラスは任意の数の抽象メンバーを定義して、すべての派生型にポリモーフィックインターフェイスを提供できることを思い出してください。ただし、クラスが一連の抽象メンバーを定義する場合でも、コンストラクター、フィールドデータ、非抽象メンバー(実装付き)などをいくつでも定義することもできます。一方、インターフェースには抽象メンバー定義のみが含まれます。抽象親クラスによって確立されたポリモーフィックインターフェイスは、派生型のみが抽象親によって定義されたメンバーをサポートするという点で、1つの大きな制限を受けます。ただし、大規模なソフトウェアシステムでは、System.Object以外に共通の親を持たない複数のクラス階層を開発することが非常に一般的です。抽象基本クラスの抽象メンバーは派生型にのみ適用されるため、同じポリモーフィックインターフェイスをサポートするように異なる階層の型を構成する方法はありません。例として、次の抽象クラスを定義したとします。

public abstract class CloneableType
{
// Only derived types can support this
// "polymorphic interface." Classes in other
// hierarchies have no access to this abstract
// member.
   public abstract object Clone();
}

この定義では、CloneableTypeを拡張するメンバーだけがClone()メソッドをサポートできます。この基本クラスを拡張しないクラスの新しいセットを作成する場合、このポリモーフィックインターフェイスを取得できません。また、C#はクラスの多重継承をサポートしていないことを思い出してください。したがって、Carであり、CloneableTypeであるMiniVanを作成したい場合は、作成できません。

// Nope! Multiple inheritance is not possible in C#
// for classes.
public class MiniVan : Car, CloneableType
{
}

ご想像のとおり、インターフェイスの種類が役に立ちます。インターフェイスが定義されると、任意のクラスまたは構造、任意の階層、任意の名前空間または任意のアセンブリ(任意の.NETプログラミング言語で記述)内に実装できます。ご覧のとおり、インターフェイスは非常に多態性です。System名前空間で定義されているICloneableという名前の標準.NETインターフェイスを考えてみます。このインターフェイスは、Clone()という名前の単一のメソッドを定義します。

public interface ICloneable
{
object Clone();
}

6

2番目の質問への回答:publicで定義された変数がinterfaceあるstatic final一方で、デフォルトではpublic、変数abstractクラスはインスタンス変数です。


6

確かに、OOPのインターフェイスと抽象クラスの動作(および言語がそれらを処理する方法)を理解することは重要ですが、各用語の正確な意味を理解することも重要だと思います。ifコマンドが用語の意味として正確に機能していないと想像できますか?また、実際には一部の言語では、インターフェイスとアブストラクトの違いがさらに小さくなっています...ある日偶然に2つの用語がほぼ同じように機能する場合、少なくともどこに(そしてなぜ)あるべきかを定義できますのために使用される。

いくつかの辞書や他のフォントを読むと、同じ用語の意味が異なる場合がありますが、いくつかの共通の定義があります。私がこのサイトで見つけたこれらの2つの意味は、本当に、非常に適切で適切だと思います。

インターフェース:

個別の、場合によっては互換性のない要素を効果的に調整できるようにする事柄または状況。

概要:

それ自体に、より広範なまたはより一般的な何か、またはいくつかのものの本質的な性質を集中させる何か。エッセンス。

例:

あなたは車を買って、それは燃料を必要とします。

ここに画像の説明を入力してください

あなたの車のモデルはXYZであり、これはジャンルABCですので、具体的な車であり、車の特定のインスタンスです。車は実際のオブジェクトではありません。実際、特定のオブジェクトを作成することは、一連の抽象的な標準(品質)です。簡単に言うと、Carは抽象クラスであり「より広範な、またはより一般的な何かの本質的な性質をそれ自体に集中させるもの」です。

車のマニュアルの仕様に一致する唯一の燃料は、車のタンクを満たすために使用する必要があります。実際には、燃料を入れることを制限するものは何もありませんが、エンジンは指定された燃料でのみ正しく動作するため、その要件に従うことをお勧めします。要件では、同じジャンルの他の車と同様ABCに、標準的な燃料のセットを受け入れるとしています。

オブジェクト指向のビューでABCは、特定のジャンルの車には具体的な燃料がないため、ジャンルの燃料をクラスとして宣言しないでください。あなたの車は抽象クラスFuelまたはVehicularFuelを受け入れることができますが、既存の車両用燃料の一部のみが仕様(車のマニュアルの要件を実装するもの)を満たすことを覚えておく必要があります。要するに、それらは、実装すべきインターフェース ABCGenreFuel「...効果的に調整するために別個の、時には互換性のない要素を可能にします」

補遺

さらに、(前述の同じサイトからの)クラスという用語の意味を覚えておく必要があると思います。

クラス:

共通の属性、特性、資質、または特性のためにグループを形成していると見なされる多くの人または物。種類;

このように、クラス(または抽象クラス)は、共通の属性(インターフェースなど)だけを表すのではなく、共通の属性を持つある種のグループを表す必要があります。インターフェイスは種類を表す必要はありません。共通の属性を表す必要があります。このように、クラスや抽象クラスは、ある種の表現であるため、人間の哺乳類のように、その側面を頻繁に変更してはならないものを表現するために使用できると思います。種類はそれほど頻繁に変わるべきではありません。


1
綿毛が多すぎる場合は、すでに混乱しているように聞こえないようにしてください。
ganjeii 16

5

コーディングの観点から

抽象クラスに抽象メソッドしかない場合、インターフェイスは抽象クラスを置き換えることができます。それ以外の場合は、抽象クラスをインターフェースに変更すると、継承が提供するコードの再利用性が失われます。

デザインの観点から

「Is a」関係であり、サブセットまたはすべての機能が必要な場合は、抽象クラスとして保持してください。「Should Do」関係の場合は、インターフェースのままにしておきます。

必要なものを決定します。ポリシーの施行、またはコードの再利用性とポリシーのみです。


3

他のいくつかの違い:

抽象クラスは静的メソッド、プロパティ、フィールドなどを持つことができ、演算子、インターフェースは持つことができません。キャスト演算子は、抽象クラスとのキャストを許可しますが、インターフェースとのキャストを許可しません。

したがって、(静的メンバーを通じて)実装されていない場合でも、抽象クラスを単独で使用でき、インターフェイスを単独で使用することはできません。


Javaでは、インターフェイスはメンバー変数を持つことができますが、デフォルトではpublic staticになります。soインターフェイスは静的フィールドを持つことができます
Jitendra Vispute

はい、インターフェースは静的フィールドを持つことができます。BUTインターフェイスに静的メソッドを含めることはできません。
2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.