用語:言語構造interface
をinterfaceと呼び、型またはオブジェクトのインターフェースをsurfaceと呼びます(より良い用語がないため)。
オブジェクトを具象型ではなく抽象化に依存させることで、疎結合を実現できます。
正しい。
これは2つの主な理由のための疎結合を可能にする1 -抽象化が依存するコードが少なく破壊することを意味し、具体的なタイプよりも変化しにくくなります。2-抽象に適合するため、実行時にさまざまな具象型を使用できます。既存の依存コードを変更する必要なしに、新しいコンクリートタイプを後で追加することもできます。
まったく正しくありません。現在の言語は、一般に抽象化が変更されることを予期していません(ただし、それを処理する設計パターンはいくつかあります)。一般的なものから詳細を分離することは抽象化です。これは通常、何らかの抽象化層によって行われます。この抽象化に基づいて構築されたコードを壊すことなく、このレイヤーを他のいくつかの詳細に変更できます。疎結合が実現されます。非OOPの例:sort
ルーチンは、バージョン1のQuicksortからバージョン2のTim Sortに変更される可能性があります。sort
したがって、ソートされる(つまり抽象化に基づいて)結果にのみ依存するコードは、実際のソートの実装から切り離されます。
私はと呼ばれる表面を上にすることで、一般的な一部の抽象化。OOPでは、1つのオブジェクトが複数の抽象化をサポートする必要がある場合があります。非常に最適ではない例:Java は、「順序付けられたインデックス可能なコレクション」抽象化に関するインターフェイスと、(大まかに言えば)「FIFO」抽象化に関するインターフェイスのjava.util.LinkedList
両方List
をサポートしQueue
ます。
オブジェクトは複数の抽象化をどのようにサポートできますか?
C ++にはインターフェイスはありませんが、複数の継承、仮想メソッド、および抽象クラスがあります。抽象化は、仮想メソッドを宣言するが定義はしない抽象クラス(つまり、すぐにインスタンス化できないクラス)として定義できます。抽象化の詳細を実装するクラスは、その抽象クラスから継承して、必要な仮想メソッドを実装できます。
ここでの問題は、多重継承がひし形の問題を引き起こす可能性があることです。そこでは、クラスがメソッド実装を検索する順序(MRO:メソッド解決順序)が「矛盾」につながる可能性があります。これには2つの応答があります。
正しい順序を定義し、合理的に線形化できない順序を拒否します。C3 MROはかなり賢明であるとうまく動作します。1996年に公開されました。
簡単なルートをたどり、全体を通して複数の継承を拒否します。
Javaは後者のオプションを採用し、単一の動作継承を選択しました。ただし、複数の抽象化をサポートするには、オブジェクトの機能が必要です。したがって、メソッド定義をサポートせず、宣言のみをサポートするインターフェイスを使用する必要があります。
その結果、MROは明らかで(各スーパークラスを順番に見るだけで)、オブジェクトは任意の数の抽象化に対して複数のサーフェスを持つことができます。
非常に多くの場合、動作の一部が表面の一部であるため、これはかなり不十分であることがわかります。Comparable
インターフェイスを考えてみましょう:
interface Comparable<T> {
public int cmp(T that);
public boolean lt(T that); // less than
public boolean le(T that); // less than or equal
public boolean eq(T that); // equal
public boolean ne(T that); // not equal
public boolean ge(T that); // greater than or equal
public boolean gt(T that); // greater than
}
これは非常にユーザーフレンドリーです(多くの便利なメソッドを持つ素晴らしいAPI)が、実装するのは面倒です。インターフェイスにはのみを含めcmp
、他のメソッドはその1つの必須メソッドに関して自動的に実装するようにします。Mixins、しかしより重要なことは、Traits [ 1 ]、[ 2 ]は多重継承のofに陥ることなくこの問題を解決します。
これは、特性が実際にMROに参加しないように特性構成を定義することで行われます。代わりに、定義されたメソッドが実装クラスに構成されます。
Comparable
インタフェースは、Scalaのように表すことができ
trait Comparable[T] {
def cmp(that: T): Int
def lt(that: T): Boolean = this.cmp(that) < 0
def le(that: T): Boolean = this.cmp(that) <= 0
...
}
クラスがその特性を使用すると、他のメソッドがクラス定義に追加されます。
// "extends" isn't different from Java's "implements" in this case
case class Inty(val x: Int) extends Comparable[Inty] {
override def cmp(that: Inty) = this.x - that.x
// lt etc. get added automatically
}
そうInty(4) cmp Inty(6)
だろう-2
とInty(4) lt Inty(6)
なりますtrue
。
多くの言語は特性をある程度サポートしており、「メタオブジェクトプロトコル(MOP)」を持つ言語は特性を追加できます。最近のJava 8アップデートでは、特性に似たデフォルトのメソッドが追加されました(インターフェースのメソッドはフォールバック実装を持つことができるため、これらのメソッドを実装するクラスを実装するためのオプションです)。
残念ながら、形質はかなり最近の発明(2002年)であるため、大規模な主流言語ではかなりまれです。