web-dev-qa-db-ja.com

インターフェイスを使用する理由、多重継承とインターフェイス、インターフェイスの利点

私はまだこのことについて少し混乱しています。今まで見つけたのは

(同様の質問はすでにここで質問されていますが、私はいくつかの他の点を指摘していました。)

  1. インターフェースは、抽象メソッドと最終フィールドのみのコレクションです。

  2. Javaには多重継承はありません。

  3. インターフェイスを使用して、Javaで複数の継承を実現できます。

  4. 継承の強みの1つは、派生クラスでベースクラスのコードを再度記述せずに使用できることです。これは、継承が存在するための最も重要なことかもしれません。

今….

Q1。インターフェイスには抽象メソッドのみ(コードなし)があるので、インターフェイスを実装している場合、それは継承であると言えますか?そのコードは使用していません。

Q2。インターフェイスの実装が継承ではない場合、インターフェイスを使用して複数の継承を実現する方法は?

Q3。とにかく、インターフェイスを使用する利点は何ですか?彼らはコードを持っていません。実装するすべてのクラスで何度もコードを記述する必要があります。

それではなぜインターフェイスを作成するのか?

注:インターフェイスが役立つケースが1つ見つかりました。その1つの例は、Runnableインターフェイスに、スレッドの機能を定義するpublic void run()メソッドがあり、このメソッドが別のスレッドとして実行されるようにコーディングが組み込まれているようなものです。したがって、スレッドで何をするかをコーディングするだけで、Restは事前に定義されています。しかし、これは抽象クラスとすべてを使用して実現することもできます。

それでは、インターフェースを使用することの正確な利点は何ですか?実際にインターフェースを使用して達成されるのは多重継承ですか?

62
gprathour

インターフェースは、最終的な静的フィールドと抽象メソッドのコレクションです(新しくJava 8がインターフェースに静的メソッドを持つサポートを追加しました)。

インターフェイスは、何らかのタスクを実行する必要があることがわかっている状況で作成されますが、その実行方法は異なる場合があります。言い換えれば、クラスが特定の方法で動作するようにインターフェースを実装すると言うことができます。

例で説明しましょう、私たちはすべて動物が何であるかを知っています。ライオンが動物であるように、猿は動物であり、象は動物であり、牛は動物です。今、私たちはすべての動物が何かを食べて眠ることを知っています。しかし、各動物が何かを食べたり眠ったりする方法は異なる場合があります。ライオンが牛が草を食べるように他の動物を狩ることによって食べるように。しかし、両方とも食べる。そのため、このような擬似コードを作成できます。

interface Animal {
    public void eat();
    public void sleep();   
}

class Lion implements Animal {
    public void eat() {
        // Lion's way to eat
    }

    public void sleep(){
         // Lion's way to sleep
    }
}

class Monkey implements Animal {
    public void eat() {
        // Monkey's way to eat
    }

    public void sleep() {
        // Monkey's way to sleep
    }
}

上記の擬似コードによると、食べたり眠ったりできるものはすべて動物と呼ばれます。すべての動物が食べて眠る必要があると言えますが、食べて眠る方法は動物によって異なります。

インターフェイスの場合、クラスの継承の場合のように実際のコードではなく、動作のみを継承します。

Q1。インターフェイスには抽象メソッドのみ(コードなし)があるので、インターフェイスを実装している場合、それは継承であると言えますか?そのコードは使用していません。

インターフェイスの実装は、別の種類の継承です。継承の子クラスが実際のコードを取得して基本クラスから再利用するため、クラスの継承とは異なります。

Q2。インターフェイスの実装が継承ではない場合、インターフェイスを使用して複数の継承を実現する方法は?

1つのクラスが複数のインターフェイスを実装できるためと言われています。しかし、この継承はクラスの継承とは異なることを理解する必要があります。

Q3。とにかく、インターフェイスを使用する利点は何ですか?彼らはコードを持っていません。実装するすべてのクラスで何度もコードを記述する必要があります。

インターフェイスを実装すると、すべての抽象メソッドをオーバーライドする必要があるクラスに強制が課されます。

私の本でもっと読む herehere

20
gprathour

Q1。インターフェイスには抽象メソッドのみ(コードなし)があるので、インターフェイスを実装している場合、それは継承であると言えますか?そのコードは使用していません。

できません。多重継承を実現するためにインターフェースは使用されません。彼らはそれをより安全に置き換えますが、少し強力ではありません。キーワードimplementsではなくextendsに注意してください。

Q2。インターフェイスの実装が継承ではない場合、インターフェイスを使用して複数の継承を実現する方法は?

ではない。インターフェイスを使用すると、1つのクラスに複数の「views」、異なるAPIまたは機能を含めることができます。例えば。クラスは同時にRunnableCallableにできますが、両方のメソッドは事実上同じことをしています。

Q3。とにかく、インターフェイスを使用する利点は何ですか?彼らはコードを持っていません。実装するすべてのクラスで何度もコードを記述する必要があります。

インターフェースは一種の多重継承であり、後者は導入する問題はありません( Diamond problem など)。

インターフェイスの使用例はほとんどありません。

  1. オブジェクトには実質的に2つのIDがあります:TankisVehicleWeaponの両方です。 Tankのインスタンスを使用できます。前者または後者のいずれかが予想されます(多態性)。これは実際にはめったにないケースであり、実際には複数の継承が優れている(または特性)有効な例です。

  2. 単純な責任:ゲーム内のTankオブジェクトのインスタンスは、スレッドで実行できるRunnableと、マウスイベントに応答するActionListenerです。

  3. コールバックインターフェイス:オブジェクトが特定のコールバックインターフェイスを実装する場合、ライフサイクルまたは他のイベントについて通知されます。

  4. マーカーインターフェイス:メソッドを追加するのではなく、instanceofを介して簡単にアクセスして、オブジェクトの機能や要望を検出します。 SerializableCloneableはこの例です。

探しているのは特性(Scalaなど)で、残念ながらJavaでは使用できません。

36

[〜#〜] kiss [〜#〜]

インターフェースを理解しようとして何日も何週間も検索しましたが、同じ一般的なヘルプを読んでいるようです。私は貢献を非難しようとはしていませんが、電球をクリックしただけだと思う​​ので、私は痛んでいます:))

Keep It Simple Stupidを好むので、インターフェースの新しい見方を紹介します。

私はカジュアルなコーダーですが、他の人がインターフェイスを理解できるように、VB.NETで書いたこのコードを投稿したいです(原則は他の言語でも同じです)。

私が間違っている場合は、フォローアップコメントで他の人に知らせてください。

説明

フォーム上の3つのボタンをそれぞれクリックすると、インターフェイス変数(_data)への異なるクラス参照が保存されます。インターフェース変数へのさまざまなクラス参照のポイントは、冗長と思われるため理解できなかったことであり、その能力はmsgboxで明らかになり、私はこれで必要なタスクを実行するためにSAMEメソッドを呼び出すだけですケース 'GetData()'。これは、インターフェイス参照変数(_data)によって現在保持されているクラスのメソッドを使用します。

だから、データを(データベース、Web、またはテキストファイルから)取得したいのですが、同じメソッド名;を使用するだけです。その実装の背後にあるコード...私は気にしません。

依存関係なしでインターフェイスを使用して各クラスコードを変更するのは簡単です。これがOOおよびカプセル化の重要な目標です。

使用する場合

クラスをコーディングし、「GetData()」のようにメソッドに同じ動詞が使用されていることに気づいた場合、そのクラスにインターフェースを実装し、そのメソッド名を抽象化/インターフェースとして使用するのがよい候補です。

私は、これがこの難しい原則で仲間の初心者を助けることを心から願っています。

Public Class Form1

Private _data As IData = Nothing

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    _data = New DataText()
    MsgBox(_data.GetData())
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    _data = New DataDB()
    MsgBox(_data.GetData())
End Sub

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
    _data = New DataWeb()
    MsgBox(_data.GetData())
End Sub

End Class

Public Interface IData
Function GetData() As String
End Interface

Friend Class DataText : Implements IData

Friend Function GetData() As String Implements IData.GetData
    Return "DataText"
End Function

End Class

Friend Class DataDB : Implements IData

Friend Function GetData() As String Implements IData.GetData
    Return "DataDB"
End Function

End Class

Friend Class DataWeb : Implements IData

Friend Function GetData() As String Implements IData.GetData
    Return "DataWeb"
End Function

End Class
9
Data

Q1。インターフェイスには抽象メソッドのみ(コードなし)があるので、インターフェイスを実装している場合、それは継承であると言えますか?そのコードは使用していません。

残念ながら、口語的な使用法では、クラスがインターフェイスを実装するときにWord inheritanceが依然として頻繁に使用されますが、interface implementationが望ましい用語です。IMO、inheritanceという用語は、具象クラスまたは抽象クラスの継承で厳密に使用する必要があります。 C++やC#などの言語では、同じ構文(つまり、Subclass : SuperclassおよびClass : Interface)は、クラスの継承とインターフェイスの実装の両方に使用されます。これは、インターフェイスでのWord inheritanceの誤用の拡散の一因となった可能性があります。 Javaは、インターフェースをextendingするのとは対照的に、クラスをimplementingする構文が異なります。これは良いことです。

Q2インターフェイスの実装が継承ではない場合、インターフェイスを使用して多重継承を実現する方法は?

クラスに複数のインターフェイスを実装し、クラスのすべてのインターフェイスに必要なすべてのメソッド、プロパティ、イベントの実装を提供することにより、構成を通じて多重継承の「効果」を実現できます。具象クラスでこれを行う一般的な手法の1つは、各内部クラス実装に実装を「結び付ける」ことにより、外部インターフェイスを実装するクラスと「has-a」(構成)関係を行うことです。 (C++などの言語は、複数の具体的な継承を直接サポートしますが、ダイヤモンドの問題のような他の潜在的な問題を作成します)。

Q3とにかく、インターフェイスを使用する利点は何ですか?彼らはコードを持っていません。実装するすべてのクラスで何度もコードを記述する必要があります。

インターフェースを使用すると、既知のインターフェースを介して通信できるため、既存のクラス(フレームワークなど)が以前に「見た」ことなく新しいクラスと対話できます。インターフェイスを契約と考えてください。このインターフェイスをクラスに実装することにより、必要な義務を満たすよう契約上拘束されます。このコントラクトが実装されると、インターフェイスを使用する他のコードとクラスを互換的に使用できるようになります。

実世界の例

「実世界」の例は、特定の国の電気コンセントを取り巻く法律と慣例(インターフェース)です。ソケットに差し込まれる各電化製品は、当局がソケットに対して定義した仕様(契約)を満たす必要があります。ライン、中性線、アース線の位置、オン/オフスイッチの位置と色、および切り替え時にinterfaceを介して供給される電圧、周波数、最大電流の適合性に。

単にワイヤをはんだ付けするのではなく、インターフェース(つまり標準の壁ソケット)を切り離す利点は、ファン、ケトル、ダブルアダプター、または来年発明される新しいアプライアンスを接続(および取り外し)できることです。 、インターフェースの設計時にこのアプライアンスは存在しませんでしたが。どうして?なぜなら、それはインターフェースの要件に適合するからです。

インターフェースを使用する理由

インターフェイスはクラスの疎結合に最適であり、ボブおじさんの主力の1つです [〜#〜] solid [〜#〜] パラダイム、特にDependency Inversion PrincipleおよびInterface Segregation Principles

簡単に言えば、クラス間の依存関係が他の具体的なクラスではなく、インターフェイス(抽象化)のみで結合されるようにすることで、インターフェイスの要件を満たす他のクラス実装で依存関係を置き換えることができます。

テストでは、依存関係のスタブとモックを使用して各クラスを単体テストできます。また、クラスと依存関係との相互作用を「スパイ」できます。

6
StuartLC

これは非常に古い質問であり、Java-8リリースではより多くの機能とインターフェイスへのパワーが追加されました。

インターフェース宣言には以下を含めることができます

  1. メソッド署名
  2. デフォルトの方法
  3. 静的メソッド
  4. 定数の定義。

インターフェイスに実装がある唯一のメソッドは、defaultおよびstaticメソッド。

インターフェイスの使用:

  1. contractを定義するには
  2. 関係のないクラスをcapabilitiesにリンクするには
  3. interchangeable実装を提供するには Strategy_pattern
  4. defaultメソッドを使用すると、ライブラリのインターフェイスに新しい機能を追加して、コードとのバイナリ互換性を確保できますこれらのインターフェースの古いバージョン用に書かれた
  5. ライブラリ内のヘルパーメソッドをstaticメソッドで整理します(別のクラスではなく、同じインターフェイスのインターフェイスに固有の静的メソッドを保持できます)

概念をよりよく理解するために、コード例については、この関連するSEの質問をご覧ください。

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

クエリに戻る:

Q1。インターフェイスには抽象メソッドのみ(コードなし)があるので、インターフェイスを実装している場合、それは継承であると言えますか?そのコードは使用していません。

Q2。インターフェイスの実装が継承ではない場合、インターフェイスを使用して複数の継承を実現する方法は?

インターフェースには、staticおよびdefaultメソッドのコードを含めることができます。これらのデフォルトメソッドは下位互換性を提供し、静的メソッドはhelper/utility関数を提供します。

Javaで真の多重継承を持つことはできません。インターフェースはそれを取得する方法ではありません。インターフェースには定数のみを含めることができます。

inheritancecapabilityに置き換えることができます。 インターフェイスは、クラスの実装に複数の機能を提供します。

Q3。とにかく、インターフェイスを使用する利点は何ですか?彼らはコードを持っていません。実装するすべてのクラスで何度もコードを記述する必要があります。

私の答えの「uses of interface」セクションを参照してください。

5
Ravindra babu

継承とは、あるクラスが別のクラス(抽象クラ​​スでも可)またはインターフェイスから派生する場合です。オブジェクト指向(継承)の最大のポイントは、コードの再利用(それを行う方法はたくさんあります)ではなく、多態性です。

多態性とは、インターフェイスを使用するコードがある場合です。インスタンスオブジェクトは、そのインターフェイスから派生した任意のクラスになります。たとえば、私はそのようなメソッドを持つことができます:public void Pet(IAnimal animal)そしてこのメ​​ソッドは、IAnimalを継承するDogまたはCatのインスタンスであるオブジェクトを取得します。または私はそのようなコードを持つことができます:IAnimal animalそして、私はこのインターフェイスのメソッドを呼び出すことができます:dogまたはCatが異なる方法で実装できるanimal.Eat()。

インターフェイスの主な利点は、一部のインターフェイスから継承できることですが、一方からのみ継承する必要がある場合は、抽象クラスも使用できます。以下に、抽象クラスとインターフェイスの違いについて詳しく説明する記事を示します。 http://www.codeproject.com/KB/cs/abstractsvsinterfaces.aspx

3
Ben

古い質問。正規のソースを誰も引用していないことに驚いています:Java:an Overviewby James Gosling、Design Patterns:Elements of Reusable Object-Oriented SoftwareGang of FourまたはEffective Javaby Joshua Bloch(他の情報源の中で)。

引用から始めます。

インターフェイスは、オブジェクトが応答するメソッドのセットの単なる仕様です。インスタンス変数や実装は含まれていません。インターフェイスは(クラスとは異なり)多重継承でき、通常のリジッドクラス継承構造よりも柔軟な方法で使用できます。 (Gosling、p.8)

ここで、仮定と質問を1つずつ見ていきましょう(Java 8の機能は自発的に無視します)。

仮定

インターフェースは、抽象メソッドと最終フィールドのみのコレクションです。

Javaインターフェースでキーワードabstractを見ましたか?いいえ。インターフェイスを抽象メソッドのコレクションと見なすべきではありません。たぶん、純粋な仮想メソッドのみを持つクラスであるC++いわゆるインターフェースに誤解されているかもしれません。 C++には、複数の継承があるため、設計上、インターフェイスはありません(持つ必要はありません)。

Goslingで説明されているように、インターフェイスは「オブジェクトが応答するメソッドのセット」と考える必要があります。インターフェースおよび関連ドキュメントをサービス契約として見たいです。そのインターフェースを実装するオブジェクトに期待できることを説明しています。ドキュメントでは、事前条件と事後条件(パラメーターがnullでなく、出力が常に正であるなど)と不変式(オブジェクトの内部状態を変更しないメソッド)を指定する必要があります。この契約は、OOPの中心です。

Javaには多重継承はありません。

確かに。

Javaは、私たちの経験では恩恵よりも悲しみをもたらすC++の、ほとんど使用されておらず、よく理解されていない、混乱を招く機能の多くを省略しています。これは主に、演算子のオーバーロード(メソッドのオーバーロードはありますが)、多重継承、および広範な自動強制で構成されます。 (ゴスリング、p.2)

追加するものはありません。

インターフェイスを使用して、Javaで複数の継承を実現できます。

いいえ、Javaには多重継承がないため、単純です。上記を参照。

継承の強みの1つは、派生クラスでベースクラスのコードを再度記述せずに使用できることです。これは、継承が存在するための最も重要なことかもしれません。

これは「実装の継承」と呼ばれます。あなたが書いたように、それはコードを再利用する便利な方法です。

しかし、重要な対応物があります。

親クラスは、多くの場合、サブクラスの物理表現の少なくとも一部を定義します。継承はサブクラスをその親の実装の詳細に公開するため、「継承はカプセル化を破る」とよく言われます[Sny86]。サブクラスの実装は、その親クラスの実装と非常に緊密になるため、親の実装が変更されると、サブクラスも強制的に変更されます。 (GOF、1.6)

(Blochのアイテム16にも同様の引用があります。)

実際、継承には別の目的もあります。

クラスの継承は、インターフェイスの継承と実装の継承を組み合わせたものです。インターフェイス継承は、1つ以上の既存のインターフェイスに関して新しいインターフェイスを定義します。実装継承は、1つ以上の既存の実装に関して新しい実装を定義します。 (GOF、付録A)

どちらもJavaでキーワードextendsを使用します。クラスの階層とインターフェイスの階層があります。最初のものは実装を共有し、2番目のものは義務を共有します。

ご質問

Q1。インターフェイスには抽象メソッドのみ(コードなし)があるので、インターフェイスを実装している場合、それは継承であると言えますか?そのコードは使用していません。**

インターフェイスの実装は継承ではありません。実装です。したがって、キーワードimplements

Q2。インターフェイスの実装が継承ではない場合、インターフェイスを使用して複数の継承を実現する方法**

Javaには多重継承はありません。上記を参照。

Q3。とにかく、インターフェイスを使用する利点は何ですか?彼らはコードを持っていません。実装するすべてのクラスで何度もコードを記述する必要があります。/では、なぜインターフェイスを作成するのですか?/インターフェイスを使用することの正確な利点は何ですかインターフェースを使用して達成するのは本当に多重継承ですか?

最も重要な質問は次のとおりです。なぜ多重継承が必要ですか?私は2つの答えを考えることができます。 2.コードを再利用します。

複数のタイプをオブジェクトに与える

OOPでは、1つのオブジェクトに異なるタイプがあります。たとえば、Javaの場合、ArrayList<E>には次のタイプがあります。SerializableCloneableIterable<E>Collection<E>List<E>RandomAccessAbstractList<E>AbstractCollection<E>、およびObject(誰も忘れていないことを願っています)。オブジェクトのタイプが異なる場合、さまざまなコンシューマーはその特異性を意識せずにオブジェクトを使用できます。 Iterable<E>が必要で、ArrayList<E>をくれますか?大丈夫です。しかし、今私がList<E>を必要とし、あなたが私にArrayList<E>を与えた場合、それも大丈夫です。等。

OOPでオブジェクトをどのように入力しますか? Runnableインターフェイスを例として取り上げましたが、この例はこの質問に対する答えを説明するのに最適です。公式のJavaドキュメントを引用します。

さらに、Runnableは、スレッドをサブクラス化せずにクラスをアクティブにする手段を提供します。

ポイントは次のとおりです。継承はtypingオブジェクトの便利な方法です。スレッドを作成しますか? Threadクラスをサブクラス化しましょう。オブジェクトに異なる型を持たせたい場合は、複数の継承を使用しましょう。ああJavaには存在しません。 (C++では、オブジェクトに異なる型を持たせたい場合は、多重継承を使用します。)

オブジェクトに複数のタイプを与える方法は? Javaでは、オブジェクトを直接入力できます。それは、クラスがimplementsRunnableインターフェイスのときに行うことです。継承のファンなら、なぜRunnableを使用するのですか?クラスがすでに別のクラスのサブクラスであるため、Aとしましょう。クラスには、ARunnableの2つのタイプがあります。

複数のインターフェイスを使用すると、オブジェクトに複数のタイプを指定できます。 implements複数のインターフェースを持つクラスを作成する必要があります。契約に準拠している限り、問題ありません。

コードを再利用

これは難しい課題です。カプセル化の解除に関するGOFを既に引用しました。他の回答では、ダイヤモンドの問題に言及しました。また、単一責任の原則について考えることもできます。

クラスには、変更する理由が1つしかありません。 (ロバートC.マーティン、アジャイルソフトウェア開発、原則、パターン、および実践)

親クラスを持つことは、クラスに自身の責任に加えて、変更する理由を与える場合があります。

スーパークラスの実装はリリースごとに変更される可能性があり、変更された場合、コードが変更されていなくてもサブクラスが破損する可能性があります。結果として、サブクラスはそのスーパークラス(Bloch、項目16)と連携して進化する必要があります。

もっと平凡な問題を追加します。クラス内のメソッドのソースコードを見つけようとしても見つけられないとき、いつも奇妙な気持ちになります。それから私は覚えている:それは親クラスのどこかに定義する必要があります。または祖父母クラスで。または、さらに高いかもしれません。この場合、優れたIDEは貴重な資産ですが、私の心には、魔法のようなものが残っています。必要なものはjavadocだけなので、インターフェイスの階層と似たものはありません。IDEにキーボードショートカットが1つあり、それを取得します。

継承ハウワーには利点があります:

サブクラスとスーパークラスの実装が同じプログラマーの制御下にあるパッケージ内で継承を使用しても安全です。また、拡張用に特別に設計および文書化されたクラスを拡張するときに継承を使用しても安全です(項目17:継承のために設計および文書化するか、禁止する)。 (ブロック、アイテム16)

Javaの「拡張用に特別に設計および文書化された」クラスの例はAbstractListです。

しかし、BlochとGOFはこれを主張しています:「継承よりも合成を好む」:

委任は、コンポジションを継承と同じくらい強力に再利用できるようにする方法です[Lie86、JZ91]。委任では、要求の処理に2つのオブジェクトが関与します。受信オブジェクトは、操作をそのデリゲートに委任します。これは、サブクラスが親クラスにリクエストを遅延させることに似ています。 (GOF p.32)

合成を使用する場合、同じコードを何度も記述する必要はありません。複製を処理するクラスを作成し、このクラスのインスタンスを実装するクラスに渡します。インタフェース。コードを再利用する非常に簡単な方法です。そしてこれは、単一責任の原則に従い、コードをよりテストしやすくするのに役立ちます。 RustとGoには継承がありません(クラスもありません)が、他のOOP言語よりもコードが冗長であるとは思わない。

さらに、コンポジションを使用する場合、コードに必要な構造と柔軟性を与えるためにインターフェイスを自然に使用していることに気付くでしょう(インターフェイスの使用例に関する他の回答を参照)。

注:コードをJava 8インターフェースと共有できます

そして最後に、最後の引用:

思い出に残るQ&Aセッション中に、誰かが彼に尋ねました[ジェームズゴスリング]:「もう一度Javaができたら、何を変えますか?」 「クラスを除外します」(ネット上のどこでも、これが本当かどうかわからない)

2
jferard

両方のメソッドが機能します(インターフェイスと多重継承)。

クイック実用的な短い答え

メソッド定義のみを持ち、コードをまったく持たないスーパークラスを持つ多重継承を使用した数年の経験がある場合、インターフェイスはより優れています。

補足的な質問は、「抽象クラスからインターフェイスにコードを移行する方法と理由」です。

アプリケーションで多くの抽象クラスを使用していない場合、またはそれをあまり経験していない場合は、インターフェイスをスキップすることをお勧めします。

インターフェイスを使用するラッシュをしないでください。

長い退屈な答え

インターフェイスは、抽象クラスと非常によく似ており、同等です。

コードに多くの抽象クラスがある場合、その時間はインターフェイスの観点から考え始めます。

抽象クラスを使用した次のコード:


MyStreamsClasses.Java

/* File name : MyStreamsClasses.Java */
import Java.lang.*;
// Any number of import statements

public abstract class InputStream {
  public void ReadObject(Object MyObject);
}

public abstract class OutputStream {
  public void WriteObject(Object MyObject);
}

public abstract class InputOutputStream 
    imnplements InputStream, OutputStream {
  public void DoSomethingElse();
}

次のものに置き換えることができます。


MyStreamsInterfaces.Java

/* File name : MyStreamsInterfaces.Java */
import Java.lang.*;
// Any number of import statements

public interface InputStream {
  public void ReadObject(Object MyObject);
}

public interface OutputStream {
  public void WriteObject(Object MyObject);
}

public interface InputOutputStream 
    extends InputStream, OutputStream {
  public void DoSomethingElse();
}

乾杯。

2
umlcat

インターフェースは、クラスがインターフェース内の機能を実装し、そのインターフェースに従って動作するように作成されます。

0
Dark Drake

Q1。インターフェイスには抽象メソッドのみ(コードなし)があるため、インターフェイスを実装している場合、それは継承であるとどのように言えますか?コードを使用していません。

同等の継承ではありません。ただ似ています。説明させてください:

VolvoV3 extends VolvoV2, and VolvoV2 extends    Volvo (Class)
VolvoV3 extends VolvoV2, and VolvoV2 implements Volvo (Interface)

line1: Volvo v = new VolvoV2(); 
line2: Volvo v = new VolvoV3(); 

Line1とline2のみが表示される場合、VolvoV2とVolvoV3は同じタイプであると推測できます。ボルボがスーパークラスであるかボルボがインターフェースであるかを推測することはできません。

Q2。インターフェイスの実装が継承ではない場合、インターフェイスを使用して複数の継承を実現する方法は?

インターフェースを使用する:

VolvoXC90 implements XCModel and Volvo (Interface)
VolvoXC95 implements XCModel and Volvo (Interface)

line1: Volvo   a = new VolvoXC90();
line2: Volvo   a = new VolvoXC95();
line3: XCModel a = new VolvoXC95();

Line1とline2のみが表示される場合、VolvoXC90とVolvoXC95が同じタイプ(Volvo)であると推測できます。 Volvoがスーパークラスであるか、Volvoがインターフェースであると推測することはできません。

Line2とline3のみが表示される場合、Volvo95がJavaでXCModelとVolvoの2つのタイプを実装していると推測できます。少なくとも1つはインターフェースである必要があります。 、たとえば、両方のクラスである可能性があるため、複数の継承。

Q3。とにかく、インターフェイスを使用するメリットは何ですか?インターフェイスにはコードがありません。実装するすべてのクラスで何度もコードを記述する必要があります。

VolvoXC90クラスを他の200クラスで使用するシステムを想像してください。

VolvoXC90 v = new VolvoXC90();

VolvoXC95を起動するためにシステムを進化させる必要がある場合、他の200クラスを変更する必要があります。

ここで、10,000,000クラスでVolvoインターフェースを使用するシステムを想像してください。

// Create VolvoXC90 but now we need to create VolvoXC95
Volvo v = new VolvoFactory().newCurrentVolvoModel(); 

現在、VolvoXC95モデルを作成するためにシステムを進化させる必要がある場合、1つのクラス、Factoryのみを変更する必要があります。

これは常識的な質問です。システムが少数のクラスのみで構成され、更新がほとんどない場合は、どこでもインターフェイスを使用すると逆効果になります。大規模なシステムの場合は、多くの苦痛を軽減し、インターフェイスを採用するリスクを回避できます。

S.O.L.I.Dの原則について詳しく読んで、「Effective Java」という本を読むことをお勧めします。経験豊富なソフトウェアエンジニアからの良い教訓があります。

0

そう。ここには、インターフェースとは何かを詳細に説明する優れた答えがたくさんあります。しかし、これはその使用の例であり、私の最高の同僚の一人が数年前にこれを私に説明したように、ここ数年で大学で学んだことは入り混じっています。

インターフェースは一種の「契約」です。利用可能ないくつかのメソッド、フィールドなどを公開します。実装の詳細は一切公開せず、返されるものと必要なパラメータのみを公開します。そして、ここには質問3への答えがあります。私が感じるのは、現代のOOPの最大の強みの1つです。

「修正によるものではなく、追加によるコード」-Magnus Madsen、AAU

下のサンプルコードはC#で記述されていますが、示されているすべてはJavaでもほぼ同じ方法で実行できます。

表示されるのはSampleAppというクラスで、IOContextという単一のフィールドがあります。 IOContextはインターフェイスです。 SampleAppは、データをどのように保存するかについては気にしませんが、「doSomething()」メソッドで保存するだけです。

開発プロセスの開始時には、データの保存が保存方法よりも重要だったため、開発者は単純にFileContextクラスを作成することを選択したと想像できます。ただし、後で、何らかの理由でJSONをサポートする必要がありました。そこで彼は、FileContextを継承するJSONFileContextクラスを作成しました。これは、実質的にFileContextの機能を持つIOContextであり、FileContexts SaveDataおよびLoadDataの置換を保存し、「書き込み/読み取り」メソッドを使用することを意味します。

JSONクラスの実装は、クラスを作成し、IOContextを継承するだけの場合と比較して、わずかな作業です。

SampleAppのフィールドは、 'FileContext'型のみである可能性がありますが、その方法では、そのクラスの子のみを使用することに制限されていました。インターフェースを作成することで、SQLiteContext実装を実行し、データベースに書き込むこともできます。SampleAppは決して知ることも気にすることもありません。また、sql liteクラスを作成した場合、コードに1つの変更を加えるだけで済みます:new JSONFileContext();代わりにnew SQLiteContext();になります

まだ古い実装があり、必要に応じてそれらに戻すことができます。何も壊しておらず、コードへの変更はすべて半行であり、一瞬のうちに元に戻すことができます。

so:変更ではなく、追加によるコード。

namespace Sample
{
    class SampleApp
    {
        private IOContext context;

        public SampleApp()
        {
            this.context = new JSONFileContext(); //or any of the other implementations
        }

        public void doSomething()
        {
            //This app can now use the context, completely agnostic of the actual implementation details.
            object data = context.LoadData();
            //manipulate data
            context.SaveData(data);
        }
    }

    interface IOContext
    {
        void SaveData(object data);
        object LoadData();
    }

    class FileContext : IOContext
    {
        public object LoadData()
        {

            object data = null;
            var fileContents = loadFileContents();
            //Logic to turn fileContents into a data object
            return data;
        }

        public void SaveData(object data)
        {
            //logic to create filecontents from 'data'
            writeFileContents(string.Empty);
        }

        protected void writeFileContents(string fileContents)
        {
            //writes the fileContents to disk
        }

        protected string loadFileContents()
        {
            string fileContents = string.Empty;
            //loads the fileContents and returns it as a string
            return fileContents;
        }
    }

    class JSONFileContext : FileContext
    {
        public new void SaveData(object data)
        {
            //logic to create filecontents from 'data'
            base.writeFileContents(string.Empty);
        }

        public new object LoadData()
        {
            object data = null;
            var fileContents = loadFileContents();
            //Logic to turn fileContents into a data object
            return data;
        }
    }

    class SQLiteContext : IOContext
    {
        public object LoadData()
        {
            object data = null;
            //logic to read data into the data object
            return data;
        }

        public void SaveData(object data)
        {
            //logic to save the data object in the database
        }
    }
}
0
user3801839