Dart 要想飛的高基礎要打牢篇三(類、泛型、庫)

介紹

Dart 要想飛的高基礎要打牢篇一(變量與操做符)html

Dart 要想飛的高基礎要打牢篇二(函數)web

本片文章有點長,主要講了 Dart 中 類、泛型和庫 幾個重要的概念。請耐心看下去。並無給出過多的解釋,我以爲你們經過實例慢慢去消化,本身去理解,纔是對你們最大的幫助。若有不合適,評論留言,下次我會給每一段代碼更多的解釋算法

Class 類

類(Class)是面向對象程序設計,實現信息封裝的基礎。類是一種用戶定義的類型。每一個類包含數聽說明和一組操做數據或傳遞消息的函數。類的實例稱爲對象。json

Dart是一門使用類和單繼承的面嚮對象語言,具備類和基於mixin的繼承。全部的對象都是一個類的實例,全部的類都繼承自Object。基於mixin的繼承意味着儘管任何一個類(除了Object)都只有一個父類,可是類主體能夠在多個類層次結構中複用。網絡

Dart的類與其它語言都有很大的區別,好比在dart的類中能夠有無數個構造函數,能夠重寫類中的操做符,有默認的構造函數,因爲dart沒有接口,因此dart的類也是接口,所以你能夠將類做爲接口來從新實現async

構造函數

使用new語句來構造一個類,構造函數的名字多是 ClassName,也能夠是 ClassName.otherNameide

var example = new Example(1, 2);  	//new 可省略 var example = Example(1, 2);
print(example); 					// Example(1, 2)

// 這種寫法是否是很像 JAVA 啊
class Example {
    int x;
    int y;
    Example(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

// 但在 Dart 中是能夠簡化成這樣的 (推薦)
class Example {
    int x;
    int y;
    Example(this.x, this.y);
}
複製代碼

命名構造函數

使用命名構造函數能夠爲一個類實現多個構造函數, 或者使用命名構造函數來更清晰的代表你的意圖函數

var example = Example.fromJson({'x': 2, 'y': 2});

class Example {
    int x;
    int y;
    
    Example(this.x, this.y);
    
    // 命名構造函數
    Example.fromJson(Map json) {
		x = json['x'];
        y = json['y'];
    }
}
複製代碼

重定向構造函數

有時候構造函數的目的只是重定向到該類的另外一個構造函數。一個重定向構造函數是沒有代碼的,在構造函數聲明後, 使用冒號調用其餘構造函數post

var example = Example.alongXAxis(0);
print(example);

class Example {
    int x;
    int y;
    
    Example(this.x, this.y);
    
    // 重定向構造函數,使用冒號調用其餘構造函數
    Example.alongXAxis(int x) : this(x, 0);
}
複製代碼

初始化列表

在構造函數體執行以前能夠初始化實例參數。 使用逗號分隔初始化表達式。初始化列表很是適合用來設置 final 變量的值測試

class Example {
    final String name;
    final int age;
    final String description;
    
    // 初始化列表
    Example(x, y) : 
    	x = x, 
    	y = y, 
    	description = description;
}
複製代碼

調用超類構造函數

  • 超類命名構造函數不會傳遞,若是但願使用超類中定義的命名構造函數建立子類,則必須在子類中實現該構造函數
  • 若是超類沒有默認構造函數,則你須要手動的調用超類的其餘構造函數
  • 調用超類構造函數的參數沒法訪問 this
  • 在構造函數的初始化列表中使用 super(), 須要把它放到最好
class Parent {
    int x;
    int y;
    
  	// 父類命名構造函數不會傳遞
    Parent.fromJson(x, y)
        : x = x,
    	y = y {
            print('父類命名構造函數');
        }
}

class Child extends Parent {
    int x;
    int y;
    
    // 若超類沒有默認構造函數,須要手動調用超類其餘構造函數 
    Child(x, y) : super.fromJson(x, y) {
        // 調用父類構造函數的參數沒法訪問 this
        print('子類構造函數');
    }
    
    // 在構造函數的初始化列表中使用 super(), 須要把它放到最好
    Child.fromJson(x, y)
        : x = x,
    	y = y,
    	super.fromJson(x, y) {
            print('子類命名構造函數');
        }
}
複製代碼

常量構造函數

注意事項:

  1. 定義 const 構造函數要確保全部實例變量都是 **final **

  2. const 關鍵字放在構造函數名稱以前

class Example {
    // 定義 const 構造函數要確保全部實例變量都是 final
    final int x;
    final int y;
    
    static final Example origin = const Example(0, 0);
    
    // const 關鍵字放在構造函數名稱以前,且不能有函數體
    const Example(this.x ,this.y);
}
複製代碼

工廠構造函數

  • 工廠構造函數是一種構造函數,與普通構造函數,工廠函數不會自動生成實例,而是經過代碼來決定返回的實例對象
  • 若是一個構造函數並不老是返回一個新的對象,則使用 factory 來定義這個構造函數
  • 工廠構造函數沒法訪問 this
class Singleton {
    String name;
    // 工廠構造函數沒法訪問this,因此這裏要用 static (這個變量是屬於類的,而不是屬於對象的)
    static Singleton _cache;
    
    // 工廠方法構造函數,關鍵字 * factory *
    factory Singleton([String name = 'singleton']) => Singleton._cache ??= Singleton._newObject(name);
    
    // 定義一個命名構造函數來生產實例
    Singleton._newObject(this.name);
}

=========================================================================================

// 工廠函數
class Massage {
  void doMassage(){
    print('按摩');
  }
}
class FootMassage extends Massage {
  @override
  doMassage() {
    print('腳底按摩');
  }
}

class BodyMassage extends Massage {
  @override
  void doMassage() {
    print('全身按摩');
  }
}

class SpecialMassage extends Massage {
  @override
  void doMassage() {
    print('特殊按摩');
  }
}

Massage massageFactory(String type){
  switch (type) {
    case 'foot':
      return new FootMassage();
    case 'body':
      return new BodyMassage();
    default:
      return new SpecialMassage();
  }
}
複製代碼

Setter 和 Getter

  • 每一個實例變量都隱含的具備一個 getter, 若是變量不是 final 的則還有一個 setter
  • 能夠經過實行 getter 和 setter 來建立新的屬性,使用 getset 關鍵字定義 getter 和 setter
  • getter 和 setter 的好處是,你能夠開使用實例變量,能夠把實例變量用函數包裹起來,而調用你代碼的地方不須要修改
class Rectangle {
    int left;
    int top;
    int width;
    int height;
    
    Rectangle(this.left, this.top, this.width, this.height);
    
   
    int get right => left + width;   					// 獲取right值
    set right(int value) => left = value - width;     	//設 置right值,同時left也發生變化
   
    int get bottom => top + height;
    set bottom(int value) => top = value - height;
}
複製代碼

抽象類

Dart 抽象類主要用於定義標準,子類能夠繼承抽象類,也能夠實現抽象類接口,抽象類經過 abstract 關鍵字來定義

  • 抽象類不能被實例化,除非定義一個工廠構造函數或者繼承它的子類能夠
  • 抽象類一般用來定義接口,以及部分實現
  • 抽象類一般具備抽象方法,抽象方法不須要關鍵字,以分號結束便可
  • 抽象方式使用時,須要重寫抽象類的成員變量和方法,包括私有的
  • 一個類能夠 implement 一個普通類。Dart 任何一個類都是接口
  • 一個類能夠 implement 多個接口

extends抽象類 和 implements的區別:

  1. 若是要複用抽象類裏面的方法,而且要用抽象方法約束子類的話咱們就用extends繼承抽象類
  2. 若是隻是把抽象類當作標準的話咱們就用 implements實現抽象類

經典案例:

// 定義一個抽象類,並定義兩個抽象方法
abstract class Animal {
    eat();
    run();
    printInfo() {
        print('我是一個抽象類裏面的普通方法');
    }
}

// 定義一個 Dog 繼承 Animal 並重寫其中的方法
class Dog extends Animal {
	@override
    eat() {
		print('小狗在吃骨頭');
    }
    
    @override
    run() {
		print('小狗在跑');
    }
}

class Cat extends Animal {
    @override
    eat() {
		print('小貓在吃老鼠');
    }
    
    @override
    run() {
        print('小貓在跑');
    }
}

main() {
    Dog dog = Dog();	// 實例化 Dog
    dog.eat();  		// 小狗在吃骨頭
    dog.run();			// 小狗在跑
    dog.printInfo();	// 我是一個抽象類裏面的普通方法
    
    Cat cat = Cat();	
    cat.eat();			// 小貓在吃老鼠
    cat.run();			// 小貓在跑
    cat.printInfo();	// 我是一個抽象類裏面的普通方法
}
複製代碼

不知道你們知不知道 @override 是個啥,能夠當作是重寫吧

可調用類

實現 call() 方法可讓類像函數同樣可以被調用

class TransferClass {
    call(String a, String b, String c) => '$a $b $c!';
}

main() {
    var transfer = TransferClass();
    var String = transfer("dart","flutter","top"); 
    print('$test');					// dart flutter top!
    print(transfer.runtimeType);	// TransferClass
    print(test.runtimeType);		// String
    print(transfer is Function);	// false
}
複製代碼

Mixin 泛型

使用泛型,不少的容器對象,在建立對象時均可以定義泛型類型,跟 Java 同樣

var list = List<String>();
var map = Map<int, String>();

// 運行時可判斷泛型
print(list is List<String>); 	// true
print(list.runtimeType);		// JSArray<String>
複製代碼

泛型函數

Dart1.21 開始可使用泛型函數

泛型函數能夠在如下幾個地方使用類型參數:

<1> 函數的返回值類型

<2> 參數的類型

<3> 局部變量的類型

main() {
    K addCache<K, V>(K key, V value) {
        K temp = key;
        print('${key} : ${value}');  // dart : flutter
       	return temp;
    }
    
    var key = addCache('dart', 'flutter');
    print(key);  // dart
}
複製代碼

泛型構造函數

要在使用構造函數時指定一個或多個類型,可將類型放在類名稱後面的尖括號<...>中

main() {
    var phone = Phone<String>('6888');
    print(phone.mobileNumber);   // 6888
}

class Phone<T> {
    final T mobileNumber;
    Phone(this.mobileNumber);
}
複製代碼

泛型限制

實現泛型類型時,您可能但願限制其參數的類型,能夠在<>裏面使用extends

main() {
    var footMessage = FootMessage();
    var message = Message<FootMessage>(footMessage);
    message.message.doMessage();	// 腳底按摩
}

class Message<T extends FootMessage> {
    final T message;
    Message(this.message);
}

class FootMessage {
    void doMessage() {
        print('腳底按摩');
    }
}
複製代碼

使用 import 去指定如何在另外一個庫的範圍內使用來自一個庫的命名空間

import 後的參數必須參數爲庫的 URL (Uniform Resource Identifier統一資源標識符)

例如,Dart web應用程序一般使用 Dart : html 庫,它們能夠像這樣導入:

import 'dart:html';
複製代碼

使用核心庫

對於內置的庫,URI 使用特殊的 dart: scheme

import 'dart:math';
import 'dart:io';
import 'dart:convert';
....

void main() {
    print(sqrt(4));  // math > 開平方2.0
}
複製代碼

載入第三方庫

對於其餘的庫,你可使用文件系統路徑或者 package: scheme

若是須要載入第三方庫咱們是須要在 pubspec.yaml 文件中聲明須要引用的庫,使用 Packages get 進行拉取

編寫 pubspec.yaml:

dependencies:
	flutter:
		sdk: flutter
	
	cupertion_icons: ^0.1.0     
	dio: ^2.1.0
複製代碼

調用:

import 'package:dio/dio.dart';   // Dio 一個很強大的網絡請求庫

void main() {
    getHttp();
}

void getHttp() async {
    try {
        Response response = await Dio().get("http://www.baidu.com");
    } catch (e) {
        print(e);
    }
}
複製代碼

在上方的例子中咱們使用了 asyncawait ,你們能夠自行預習,下篇文章應該會講到

載入文件

咱們先建立一個 mylib.dart 的文件,並寫入如下內容,寫啥都沒關係,隨便寫

class MyLib {
    String name;
    static MyLib _cache;
    factory MyLib([String name = 'singleton']) => MyLib._catch ??= MyLib._newObject(name);
    
    MyLib._newObject(this.name);
}
複製代碼

咱們在另外一個文件中引入 mylib.dart 文件, 我這裏是同一級目錄,因此直接這麼引入哈

import 'mylib.dart';

void main() {
    var myLib = MyLib();  // 實例化 mylib.dart 中的類
}
複製代碼

指定庫前綴

若是兩個庫有衝突的標識符,能夠爲其中一個或兩個庫都指定前綴來避免衝突

假設咱們有 mylib1.dartmylib2.dart 這兩個文件都有一個名爲 MyLib 的類

class MyLib() {
	String name;
    MyLib(this.name);
}
複製代碼

這個時候咱們須要在一個地方同時引入這兩個文件,並實例化 MyLib

import 'mylib1.dart';
import 'mylib2.dart';
   
void main() {
	var myLib1 = MyLib();
    var myLib2 = MyLib();
}
複製代碼

不用我說了,你們看着都有問題,那咱們是否是能夠指定一個前綴(別名) 呢, 在dart裏可使用 as 來爲引入的文件指定一個前綴

import 'mylib1.dart' as lib1;
import 'mylib2.dart' as lib2;
   
void main() {
	var myLib1 = lib1.MyLib();
    var myLib2 = lib2.MyLib();
}
複製代碼

選擇性載入

若是你只須要使用庫的一部分功能,則能夠選擇須要導入的內容

  • show 只載入庫的某些部分
  • hide 篩選掉庫的某些部分
import 'mylib1.dart' as lib1 show Test
import 'mylib2.dart' as lib2 hide Test
複製代碼

延遲載入

  1. 使用 await 關鍵字暫停代碼執行一直到庫加載完成
  2. 可提升程序的啓動速度
  3. 用在不常使用的功能
  4. 用在載入時間過長的包
  5. 執行 A/B 測試,例如嘗試各類算法的不一樣實現

使用 deferred as 導入,使用標識符調用 loadLibrary() 加載庫

import 'mylib1.dart' deferred as lazyLib;

void main() {
	lazyLoad()''
}

lazyLoad () async {
    await lazyLib.loadLibrary();
	var t = lazyLib.Test();
    t.test();
}
複製代碼

自定義庫

用 library 來來命名庫,用part來指定庫中的其餘文

  1. part 能夠把一個庫分開到多個 Dart 文件中

  2. 或者咱們想讓某一些庫共享它們的私有對象的時候,能夠須要使用 part

  3. import 不會徹底共享做用域,而 part 之間是徹底共享的。若是說在A庫中import了B庫,B庫import了C庫,A庫是沒有辦法直接使用C庫的對象的。而B,C如果A的part,那麼三者共享全部對象。而且包含全部導入

注意:沒必要在應用程序中(具備頂級main()函數的文件)使用library,但這樣作可讓你在多個文件中執行應用程序

// mylib/tool.dart
part of mylib;
void printTool() => print('tool')
複製代碼
// mylib/util.dart
part of mylib;
void printUtil() => print('util');
複製代碼
// mylib/mylib.dart
library mylib;

part 'util.dart';
part 'tool.dart';

void printMyLib() => print('mylib');
複製代碼
import 'mylib/mylib.dart';

void main() {
  printMyLib();
  printUtil();
  printTool();
}

複製代碼

結尾

Dart 要想飛的高基礎要打牢篇一(變量與操做符)

Dart 要想飛的高基礎要打牢篇二(函數)

我的博客 能夠根據博客右上角的 qq 圖標直接聯繫我哈

通過這幾篇文章的講解,dart的基礎已經差很少了,大概還有一兩篇內容,dart 文章就要結束了,到時候開始帶你們走進flutter的世界,謝謝你們,勞煩您的小手能夠爲我點個贊。講的很差的地方也請留言給我提示,謝謝你們

相關文章
相關標籤/搜索