10

私はDartのドキュメントを読んでいて、インターフェイスの使用方法について、Rubyから来たためか、少し混乱していました。もちろん、インターフェースはDartに固有のものではなく、インターフェースをいつ使用すべきかについてはかなりの数の説明があります。たとえば、これは、インターフェイスはチームに所属している場合にのみ役立つと言っているようです。誰もが他の誰かのコードを読んで再利用するオープンソースの世界では、それはどういう意味でしょうか?

私が見た興味深い説明の1つは、インターフェースが使用されていることを示唆しているようです。

  1. 多重継承がない言語では、
  2. そのことについては、それらはどういうわけか多重継承がないための回避策として機能します。

わかりません。Rubyのモジュールは、実際のボディで実際のメソッドを定義できるため、回避策であることを理解しています。インターフェイスでは、それを実装するクラスが持つべきメソッドを定義することしかできません。キャッチは何ですか?インターフェイスを使用することの価値をすぐに確認できる、本当に便利な例を誰かに教えてもらえますか?

PS関連するメモとして、Dartで多重継承を使用する方法はありますか?

4

3 に答える 3

26

更新:interfaceキーワードはDartから削除されました


インターフェイスは、渡される型がインターフェイスの要件を満たしていることを検証しながら、クラスの実装を切り替えることができるので便利です。

次の(よく使用される)例を見てください。

interface Quackable {
  void quack();
}

これは、次のようなメソッドに渡されるクラスの要件を定義します。

sayQuack(Quackable quackable) {
   quackable.quack();
}

これにより、次のようなQuackableオブジェクトの実装を利用できます。

class MockDuck implements Quackable {
  void quack() => print("quack");
}

class EnterpriseDuck implements Quackable {
  void quack() {
    // connect to three enterprise "ponds"
    // and eat some server bread
    // and say "quack" using an messaging system
  }

}

これらの実装は両方ともsayQuack()関数で機能しますが、一方が他方よりも大幅に少ないインフラストラクチャを必要とします。

sayQuack(new EnterpriseDuck());
sayQuack(new MockDuck());

私は、Javaの世界では、「エンタープライズアヒル」を利用するソリューションを構築するときに、このパターンを常に使用しています。ローカルで開発する場合、必要なのは、sayQuack()関数を呼び出して、ハードコードされたモックデータを返すことだけです。

ダックタイピング

Dartはオプションで入力されるため、実際にインターフェイスを使用する必要はありません。正しいメソッドシグネチャを含むクラスを作成するだけで機能します(ただし、ツールはそれを検証できません)。

class Person {   // note: no implements keyword
  void quack() => "I'm not a duck";
}

sayQuack(new Person()); // provides the quack method, so this will still work

すべてのクラスはインターフェースです

最後に、すべてのクラスもインターフェースです。これは、サードパーティのシステムがインターフェイスを使用せずに作成された場合でも、それがインターフェイスであるかのように具象クラスを使用できることを意味します。

たとえば、次のエンタープライズライブラリを想像してみてください。

class EnterpriseDuck { // note: no implements keyword
  void quack() {
    // snip
  }
}

sayQuack(EnterpriseDuck duck) {  // takes an instance of the EnterpriseDuck class
  duck.quack();
}

そして、タイプチェッカーが検証できる方法で、モックダックをsayQuackメソッドに渡します。EnterpriseDuckをインターフェイスとして使用するだけで、mockDuckを作成して、EnterpriseDuckによって暗黙的に示されるインターフェイスを実装できます。

class MockDuck implements EnterpriseDuck {
  void quack() => "I'm a mock enterprise duck";
}

多重継承

多重継承に関しては、これはDartでは不可能です。ただし、複数のインターフェースを実装し、必要なメソッドの独自の実装を提供することはできます。例:

class MultiDuck implements Quackable, EnterpriseDuck, Swimable {
  // snip...
}

インターフェイスはデフォルトのクラスを持つことができます

Dartを使用すると、ほとんどの「クラス」が実際にはインターフェイスであることがわかります。リスト、文字列などはすべて、デフォルトの実装が提供されているインターフェイスです。電話するとき

List myList = new List();

実際にはリストインターフェイスを使用しており、新しいキーワードはインターフェイスから基になるデフォルトのリスト実装にリダイレクトします。

チームでの開発に関して

インターフェイスは、オープンソースの世界でもチーム開発に役立ちます。インターフェイスは、コンポーネントが私のコンポーネントと連動するように構築する必要のあるメソッドとプロパティを定義します。そのインターフェイスの独自のテスト実装を構築できます。また、そのインターフェイスの具体的な実装を構築できます。両方が完了したら、統合できます。公開された共有インターフェースがなければ、実際に始める前に具体的な実装を提供する必要があります。

お役に立てば幸いです。

于 2012-05-08T19:24:00.460 に答える
4

基本的に、インターフェースは多重継承とは何の関係もありません。多重継承を偽造してインターフェースを悪用することは可能ですが、真の多重継承(またはミックスインまたはトレイト)が必要な場合は、ダートはそれらを提供しません(現在-ミックスインはいつか道を見つけると思います)。

インターフェースに適しているのは明示的なコントラクトです。2つのコンポーネントがAありB、それらが相互に連携する必要があるとします。確かに直接電話をかけることができBAそれは機能しますが、次に変更したいときは、それがどのように使用されているかBを確認する必要がありますA。これBは、明示的なインターフェースを公開しなかったためです。はい、インターフェースの正しい言葉は実装されていませんが、公開されています。

の実装をインターフェースの背後に隠し、Bそのインターフェースのみをに提供するA場合は、自由に変更でき、同じインターフェースを公開することBだけを心配する必要があります。インターフェイスは複数のクラスによって公開されることもあり、呼び出し元は気にする必要はありません(または知る必要もありません)。

ここで、インターフェースという言葉には2つの意味があることに注意してください。コンポーネントの一般的な契約(ドキュメントでは平易な英語で説明することもできます)と、契約の一部を内部で説明(および実施)するのに役立つ特別な言語構造です。プログラミング言語。

必ずしも言語構造を使用する必要はありませんが、プログラミング言語で許可されているコントラクトの部分を記述するために使用するのが適切なスタイルと見なされます。

さて、ここでの契約は一体何ですか?簡単に言えば、コントラクトは、コンポーネントがユーザーに期待することと、ユーザーがコンポーネントに期待できることの説明です。

たとえば、数値の絶対値を計算するメソッドがあるとします。

class MathUtils {
  /// Computes absolute value of given [number], which must be a [num].
  /// Return value is also a [num], which is never negative.
  absoluteValue(number) {
    ... here's the implementation ...
  }
}

ここでの契約は、ドキュメントのコメントで完全に説明されています(完全ではありませんが、絶対値を説明することもできますが、これで十分です)。ええと...でもコメントの一部は言語で直接表現できますよね?

class MathUtils {
  /// Computes absolute value of given [number].
  /// Return value is never negative.
  num absoluteValue(num number) {
    ... here's the implementation ...
  }
}

契約の一部はプログラミング言語で表現できないことに注意してください。ここでは、言語は絶対値が何であるかを認識していないため、コメントに残す必要があります。また、戻り値が決して負になることはないので、これもコメントに残しておく必要があります。しかし実際には、コードの読者は絶対値が何であるか(そしてそれが負になることは決してないこと)を知っており、メソッド名は目的についてかなり明確であるため、コメントは完全に省略できます。

class MathUtils {
  num absoluteValue(num number) {
    ... here's the implementation ...
  }
}

そのため、現在、契約の一部は言語手段を使用して明示的に表現され、一部は暗黙的に表現されています(絶対値が何であるかを知っている人々に依存しています)。

また、言語のインターフェースは、コントラクトを実装から切り離すために使用されます。小さなプログラムで使用するのはおそらくやり過ぎですが、大きなプログラムを実行する場合は効果があります(チームワークを伴う必要はありません)。

うーん、これは私が予想していたよりも長いことが判明しました。お役に立てば幸いです。

于 2012-05-09T07:13:52.583 に答える
1

インターフェイスはDartの型システムの一部であり、型宣言はオプションです。これは、インターフェースもオプションであることを意味します。

インターフェイスは、オブジェクトが応答するメソッドを文書化するのに役立ちます。インターフェイスを実装する場合は、インターフェイスのすべてのメソッドを実装することを約束します。

Dartはこの情報を使用して、型の不一致に関するコンパイル時の警告を表示し、コードアシストのより役立つ提案を提供し、一部のリファクタリングを支援します。

于 2012-05-08T16:42:39.143 に答える