簡體   English   中英

什么時候在Dart中使用接口?

[英]When to use interfaces in Dart?

我正在閱讀Dart的文檔,我有點困惑,也許是因為我來自Ruby,關於如何使用接口。 當然,接口不是Dart獨有的,當有人應該使用接口時,有很多解釋。 這其中 ,例如,似乎是說,當你在一個團隊是接口僅僅是有用的。 它甚至應該在開源世界中意味着什么,每個人都在閱讀和重用其他人的代碼?

我見過的一個有趣的解釋似乎暗示使用了接口:

  1. 在缺乏多重繼承的語言中,和
  2. 就此而言,它們在某種程度上可以作為缺少多重繼承的解決方法。

我不明白。 我知道Ruby中的模塊是一種解決方法,因為它們允許我用實際的主體定義真實的方法。 接口只允許我定義實現它的類應該具有的方法。 有什么收獲? 任何人都可以告訴我一個真正有用的例子,我可以立即看到使用接口的價值?

PS在相關的說明中,有沒有辦法在Dart中使用多重繼承?

更新: 從Dart中刪除了interface關鍵字


接口很有用,因為它們允許您切換類的實現,同時仍允許驗證傳入的類型是否滿足接口的要求。

采用以下(常用)示例:

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方法。 您可以創建mockDuck來實現EnterpriseDuck隱含的接口,只需使用EnterpriseDuck作為接口:

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

多重繼承

就多重繼承而言,這在Dart中是不可能的。 但是,您可以實現多個接口並提供所需方法的實現,例如:

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

接口可以有默認類

當你使用Dart時,你會發現大多數“類”實際上都是接口。 List,String等...都是提供默認實現的接口。 你打電話的時候

List myList = new List();

您實際上正在使用List接口,new關鍵字從接口重定向到基礎默認List實現。

關於在團隊中發展

接口在團隊開發中很有用,即使在開源世界中也是如此。 該接口定義了您應該構建的方法和屬性,以便您的組件可以與我的組件一起使用。 您可以構建自己的該接口的測試實現,並且我可以構建該接口的具體實現,當我們完成后,我們可以集成。 如果沒有已發布的共享界面,我需要在您真正開始之前提供我的具體實現。

希望有所幫助!

基本上,接口與多重繼承無關。 在執行此操作時可以偽造多個繼承和濫用接口,但如果您想要真正的多重繼承(或mixins或traits),那么Dart不提供它們(目前 - 我相信mixins會在某一天找到它們的方式)。

什么是接口有利於明確的合同 假設您有兩個需要相互協作的組件AB 你肯定可以撥打BA直接,它會工作,但下一次你會想改變B ,你將不得不尋找A它是如何使用它。 那是因為B沒有公開顯式接口 是的,接口的正確單詞不是實現,而是公開

如果在接口后面隱藏B的實現並僅將該接口提供給A ,那么您可以隨意更改B並且只擔心仍然暴露相同的接口 接口甚至可以由多個類公開,並且調用者不必關心(甚至不知道)。

請注意,單詞interface在這里有兩個含義:組件的一般契約 ,也可以在文檔中用簡單的英語描述,以及一個特殊的語言結構 ,可以幫助您描述(並執行)合同中的某些部分編程語言。

您不一定非必須使用語言構造,但使用它來描述編程語言允許的合同的那些部分被認為是好的風格。

現在,這里的合同到底是什么? 簡而言之,contract是對組件期望的用戶以及用戶對組件的期望

例如,假設我有一個計算數字絕對值的方法:

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 ...
  }
}

所以現在,合同的某些部分是使用語言手段明確表達的,而某些部分是隱式表達的(你依賴於人們知道絕對值是什么)。

語言中的接口用於將合同與實現分離 在小型程序中使用它可能有點過分,但是在執行更大的程序(不需要涉及團隊工作)時會有所回報。

事實證明,這比我預期的要長。 希望有所幫助。

接口是Dart中類型系統的一部分,類型聲明是可選的。 這意味着接口也是可選的。

接口可幫助您記錄對象響應的方法。 如果您實現了接口,那么您承諾在接口中實現所有方法。

Dart使用此信息來顯示類型不匹配的編譯時警告,為代碼輔助提供更有用的建議並協助進行一些重構。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM