重複の可能性:
C#でインターフェイスと拡張メソッドの代わりに抽象クラスを使用する場合?
抽象クラスではなくインターフェイスを作成する理由は他にありますか?
この質問は、私自身もそれを真剣に考えるまで、私にとっても些細なことのように思えました。
Javaインターフェースの意味は何ですか?それは多重継承に対する本当にJavaの答えですか?
しばらくインターフェースを使用しているにもかかわらず、私はこれのすべてのポイントを考えるために動き回ることはありませんでした。私はインターフェースが何であるかを知っていますが、その理由についてはまだ考えています。
Javaでは、インターフェースの多重継承が可能です。単一継承は実装用です。
インターフェースは、クラスが行うこととその方法を分離するため、重要です。クライアントが何を期待できるかを定義する契約は、契約を守る限り、開発者が自由に実装できるようにします。
この例はJDK全体に表示されます。 Java.sqlパッケージを見てください。これは、インターフェースがたくさんあります。どうして?そのため、さまざまなリレーショナルデータベースを自由に使用して、特定の製品にこれらのメソッドを実装できます。クライアントは、インターフェース参照タイプのみを処理する必要があります。リレーショナルデータベースの変更は、JDBCドライバーJARを別のJARに交換するのと同じくらい簡単です。クライアントを変更する必要はありません。 (契約から逸脱しない限り)。
動的プロキシとアスペクト指向プログラミングはインターフェースに依存しています。そのようにして、実行時に実装を置き換えることができます。
コードを柔軟にするために、具体的な実装ではなくインターフェイスに対してプログラミングします。
例えば、
必要に応じてIScrewDriver
またはPhilipsScrewDriver
を使用できるように、FlatScrewDriver
に対してプログラミングします。
通常、コードに適切なドライバーを「挿入」するために、ある種のIoCコンテナーを使用しますが、それは必ずしも必要ではありません。
例がお役に立てば幸いです。
Javaインターフェースのポイントは何ですか?
ポイントは、API(何をすべきか)を実装(どのようにそれを行うか)から分離することです。
Javaでは関数参照を渡すことができないため、コールバックを使用する場合もインターフェイスが必要です。
それは本当に多重継承に対するJavaの答えですか?
とりわけ、そうです。厄介な複雑化なしに、MIの機能のいくつかを提供します。
Javaに多重継承のための独自の構成がある、つまり interface
およびabstract
クラスを使用する理由はたくさんあります。ここに3つあります私が考えることができること:
interface
構成を持たない言語では、多くのボイラープレートコーディングを行う必要があります。 C++では、純粋な仮想関数を持つクラスを作成する必要があると考えてください。
_class MyInterface
{
public:
virtual void show() = 0;
virtual int number() = 0;
};
class ConcreteImpl : public MyInterface
{
public:
void show()
{
cout << "Concrete Impl here";
}
int number()
{
return 1337;
}
};
_
Javaの同等のものは、ほとんどの場合、メソッドが仮想(オーバーライド可能)関数であるため、冗長ではありません。また、アーチファクトの1つがインターフェースであることは明らかです。
_interface MyInterface {
void show();
int number();
}
class ConcreteImpl implements MyInterface {
public void show() {
System.out.println("Concrete Impl here");
}
public int number() { return 1337; }
}
_
Javaは、abstract
キーワードを使用して、純粋な仮想と実装が混在するクラスを許可します。
複数の継承に関連する問題の1つは、毛深い ダイヤモンドの継承の問題 です。 C++などの言語でこの一連のクラスを許可する言語があるかどうかを検討してください。
2つのSuperBaseClass
を実装したBaseClass
を考えてください。どちらもSuperBaseClass
のメソッドを仮想関数として実装しています。次に、両方のBaseClass
がMyImplementation
クラスによって実装されます。 super()
でMyImplementation.draw()
を呼び出すとどうなるか考えてみてください。 C++でさえ、何が起こるかが常に明らかであるとは限りません。
ダイヤモンドの継承には特に問題はないため、スーパーメソッドを呼び出す問題を回避するには、純粋な仮想関数を使用するか、よりスマートな方法で設計する必要があります。 Javaでは、デフォルトですべてのメソッドが仮想であるため、interface
sには実装が含まれていないため(implements
キーワードを使用)、多重継承しか実行できないという制約を受けます。 。他のクラスは、abstract
のクラスであっても、単一の継承のみが可能です(extends
キーワードを使用)。
GoFによるDesign Patterns に入ると、拡張可能なシステムを設計するためにインターフェースに大きく依存していることがわかります。実際、デザインパターンの原則の1つは次のとおりです。
「「実装」ではなく「インターフェース」へのプログラム。」 (ギャングオブフォー1995:18)
GoFの意味でのインターフェースは、実装ではなくスーパークラスに向けてプログラミングする必要があることを意味します。たとえば、変数を_Collection<T>
_ではなく_Iterable<T>
_、_List<T>
_、または_ArrayList<T>
_ではなくJava ifオブジェクトで使用するメソッドはそれを反復することだけです。GoFのパターン例は 戦略パターン です。この場合、コンテキストは実行するために指定された正確な戦略を知る必要はありませんが、実行されますそれが何であったかに関係なく、セット1。
これは私が何かに気づくまで私を困惑させていました:
基本的に、インターフェースは抽象メソッドのみを含む単なるクラスです。このようなエンティティをインターフェイスにすることで、クラスにはない柔軟性が得られます。
見つかりました このリンク は本当に便利です。私にとって理にかなっているいくつかの抜粋:
...インターフェイスと実装の分離は、Java一般に背後にある主要なアイデアの1つです。たとえば、Java仮想マシン(JVM)は、プログラムが基礎となる実際のコンピューターと「インターフェース」する方法を定義する抽象コンピューター。Windowsで実行されるJVMはその抽象コンピューターの実装の1つです。Macintoshで実行されるJVMは別の実装です。腕時計で実行されるJVMはまだありません別の
インターフェースを使用すると、すべてを1つのクラスファミリーに適合させる必要がないため、インターフェースは、単一継承クラスファミリーよりも多くのポリモーフィズムを提供します。
インターフェイスを使用することで、システムの各部分を互いに分離し、より柔軟なコードを生成します。コードの変更、拡張、カスタマイズがより簡単になります。
A implements B, C
はA extends B, C
とは異なります
かなりはっきりしているように見えますが、インターフェイスも多重継承の欠如に対する答えであると人々が言うとき、私も常に混乱していました。
this link は、インターフェースを使用しているときに多重継承をシミュレートする方法があることを示しています。しかし、インターフェースは多重継承の実装を直接支援していません。
インターフェイスは、複数のサブタイピング用だと思います。上記の例では、AはタイプBとCの両方です。したがって、AはBのメンバーまたはCのメンバーのいずれかに置き換えることができます( このWikipediaの記事 を参照)。
単一のインターフェースの複数の実装がある可能性があるため、動的なポリモーフィズムにも役立ちます。コードは、実装(コンテキストに基づいて動的に置き換えることができる)ではなく、タイプ(インターフェース)に依存します。
はい、インターフェースはJavaの多重継承に対する答えです。複数のクラスが祖先に参加できる一方で複数のクラスは参加できないという事実を除いて、抽象クラスが実行できないことは、インターフェイスが実行できることにはまったく何もありません。
したがって、子孫に特定の基本クラスを強制的に拡張するのではなく、子孫が自由に基本クラスを拡張できるように(そしてインターフェースを実装するために)、抽象クラスの代わりにインターフェースを使用します。