欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Flutter 語法進階抽象類和接口本質(zhì)區(qū)別詳解

 更新時間:2022年08月16日 09:13:56   作者:張風(fēng)捷特烈  
這篇文章主要為大家介紹了Flutter 語法進階抽象類和接口本質(zhì)區(qū)別詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

1. 接口存在的意義?

在 Dart 中 接口 定義并沒有對應(yīng)的關(guān)鍵字。可能有些人覺得 Dart 中弱化了 接口 的概念,其實不然。我們一般對接口的理解是:接口是更高級別的抽象,接口中的方法都是 抽象方法 ,沒有方法體。通過接口的定義,我們可以通過定義接口來聲明功能,通過實現(xiàn)接口來確保某類擁有這些功能。

不過你有沒有仔細(xì)想過,為什么接口會存在,引入接口的概念是為了解決什么問題?可能有人會說,通過接口,可以規(guī)范一類事物的功能,可以面向接口進行操作,從而可以更加靈活地進行拓展。其實這只是接口的作用,而且這些功能 抽象類 也可以支持。所以接口一定存在什么特殊的功能,是抽象類無法做到的。

都是抽象方法的抽象類,和接口有什么本質(zhì)的區(qū)別呢?在我的初入編程時,這個問題就伴隨著我,但漸漸地,這個問題好像對編程沒有什么影響,也就被遺忘了。網(wǎng)上很多文章介紹 抽象類 和 接口 的區(qū)別,只是在說些無關(guān)痛癢的形式區(qū)別,并不能讓我覺得接口存在有什么必要性。

思考一件事物存在的本質(zhì)意義,可以從沒有這個事物會產(chǎn)生什么后果來分析?,F(xiàn)在想一下,如果沒有接口,一切的抽象行為僅靠 抽象類 完成會有什么局限性 或說 弊端。沒有接口,就沒有 實現(xiàn) (implements) 的概念,其實這就等價于在問 implements 消失了,對編程有什么影響。沒有實現(xiàn),類之間就只能通過 繼承 (extends) 來維護 is-a 的關(guān)系。所以就等價于在問 extends 有什么局限性 或說 弊端。答案呼之欲出:多繼承的二義性 。

那問題來了,為什么類不能支持 多繼承 ,而接口可以支持 多實現(xiàn) ,繼承 和 實現(xiàn) 有什么本質(zhì)的區(qū)別呢?為什么 實現(xiàn) 不會帶來 二義性 的問題,這是理解接口存在關(guān)鍵。

2. 繼承 VS 實現(xiàn)

下面我們來探討一下 繼承 和 實現(xiàn) 的本質(zhì)區(qū)別。如下 A 和 B 類,有一個相同的成員變量和成員方法:

class A{
  String name;
  A(this.name);
  void run(){  print("B"); }
}
class B{
  String name;
  B(this.name);
  void run(){ print("B"); }
}

對于繼承而言 派生類 會擁有基類的成員變量與成員方法,如果支持多繼承,就會出現(xiàn)兩個問題:

  • 問題一 : 基類中有同名 成員變量 ,無法確定成員的歸屬類
  • 問題二: 基類中有同名 成員方法 ,且子類未覆寫。在調(diào)用時,無法確定執(zhí)行哪個。
class C extends A , B {
  C(String name) : super(name); // 如果多繼承,該為哪個基類的 name 成員賦值 ??
}
void main(){
  C c = C("hello")
  c.run(); // 如果多繼承,該執(zhí)行哪個基類的 run 方法 ??
}

其實仔細(xì)思考一下,一般意義上的接口之所以能夠 多實現(xiàn) ,就是通過限制,對這兩個問題進行解決。比如 Java 中:

  • 不允許在接口中定義普通的 成員變量 ,解決問題一。
  • 在接口中只定義抽象成員方法,不進行實現(xiàn)。而是強制派生類進行實現(xiàn),解決問題二。
abstract class A{
  void run();
}
abstract class B{
  void run();
}
class C implements A,B{
  @override
  void run() {
    print("C");
  }
}

到這里,我們就認(rèn)識到了為什么接口不存在 多實現(xiàn) 的二義性問題。這就是 繼承 和 實現(xiàn) 最本質(zhì)的區(qū)別,也是 抽象類 和 接口 最重要的差異。從這里可以看出,接口就是為了解決多繼承二義性的問題,而引入的概念,這就是它存在的意義。

3. Dart 中接口與實現(xiàn)的特殊性

Dart 中并不像 Java 那樣,有明確的關(guān)鍵字作為 接口類 的標(biāo)識。因為 Dart 中的接口概念不再是 傳統(tǒng)意義 上的狹義接口。而是 Dart 中的任何類都可以作為接口,包括普通的類,這也是為什么 Dart 不提供關(guān)鍵字來表示接口的原因。

既然普通類可以作為接口,那多實現(xiàn)中的 二義性問題 是必須要解決的,Dart 中是如何處理的呢? 如下是 A 、B 兩個普通類,其中有兩個同名 run 方法:

class A{
  void run(){
    print("run in a");
  }
}
class B{
  void run(){
    print("run in a");
  }
  void log(){
    print("log in a");
  }
}

當(dāng) C 類實現(xiàn) A 、B 接口,必須強制覆寫 所有 成員方法 ,這點解決了二義性的 問題二 :

那 問題一 中的 成員變量 的歧義如何解決呢?如下,在 A 、B 中添加同名的成員變量:

class A{
  final String name;
  A(this.name);
  // 略同...
}
class B{
  final String name;
  B(this.name);
  // 略同...
}

當(dāng) C 類實現(xiàn) A 、B 接口,必須強制覆為 所有 成員變量提供 get 方法 ,這點解決了二義性的 問題一 :

這樣,C 就可以實現(xiàn)兩個普通類,而避免了二義性問題:

class C implements A, B {
  @override
  String get name => "C";
  @override
  void log() {}
  @override
  void run() {}
}

其實,這是 Dart 對 implements 關(guān)鍵字的功能加強,迫使派生類必須提供 所有 成員變量的 get 方法,必須覆寫 所有 成員方法。這樣就可以讓 類 和 接口 成為兩個獨立的概念,一個 class 既可以是類,也可以是接口,具有雙重身份。

其區(qū)別在于,在 extend 關(guān)鍵字后,表示繼承,是作為類來對待;

在 implements 關(guān)鍵字之后,表示實現(xiàn),是作為接口來對待。

4.Dart 中抽象類作為接口的小細(xì)節(jié)

我們知道,抽象類中允許定義 普通成員變量/方法 。下面舉個小例子說明一下 繼承 extend 和 實現(xiàn) implements 的區(qū)別。對于繼承來說,派生類只需要實現(xiàn)抽象方法即可,抽象基類 中的普通成員方法可以不覆寫:

而前面說過,implements 關(guān)鍵字要求派生類必須覆寫 接口 中的 所有 方法 。也就表示下面的 C implements A 時,也必須覆寫 log 方法。從這個例子中,可以很清楚地看出 繼承 和 實現(xiàn) 的差異性。

抽象類 和 接口 的區(qū)別,就是 繼承 和 實現(xiàn) 的區(qū)別,在代碼上的體現(xiàn)是 extend 和 implements 關(guān)鍵字功能的區(qū)別。只有理解 繼承 的局限性,才能認(rèn)清 接口 存在的必要性。

以上就是Flutter 語法進階抽象類和接口本質(zhì)區(qū)別詳解的詳細(xì)內(nèi)容,更多關(guān)于Flutter 語法抽象類接口的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論