Dart抽象类, 多态, 接口, 泛型和库

抽象类

Dart抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口

  1. 抽象类通过abstract关键字来定义
  2. Dart中的抽象方法不能用abstract声明,Dart中没有方法体的方法我们称为抽象方法。
  3. 如果子类继承抽象类必须得实现里面的全部抽象方法
  4. 如果把抽象类当做接口实现的话必须得实现抽象类里面定义的所有属性和方法。
  5. 抽象类不能被实例化,只有继承它的子类可以

extends抽象类和implements的区别:

  1. 如果要复用抽象类里面的方法,并且要用抽象方法约束自类的话我们就用extends继承抽象类
  2. 如果只是把抽象类当做标准的话我们就用implements实现抽象类
案例
  • 定义一个Animal类要求它的子类必须包含eat方法
abstract class Animal {
  eat(); // 抽象方法
  printInfo() {
    print("我是抽象类中的普通方法");
  }
}

class Dog extends Animal {
  @override
  eat() {
    // TODO: implement eat
    print("小狗在吃骨头");
  }
}

class Cat extends Animal {
  @override
  eat() {
    // TODO: implement eat
    print("小猫在吃鱼");
  }
}

void main() {
  Dog d = new Dog();
  d.eat();
  d.printInfo();
  Cat c = new Cat();
  c.eat();
  c.printInfo();
}

输出结果:

小狗在吃骨头

我是抽象类中的普通方法

小猫在吃鱼

我是抽象类中的普通方法

多态

  1. 允许将子类类型的指针赋值给父类类型的指针,同一个函数调用会有不同的执行效果。
  2. 子类的实例赋值给父类的引用。
  3. 多态就是父类定义一个方法不去实现,让继承他的子类去实现,每个子类有不同的表现。

上面的例子就是多态的呈现。

Animal d = new Dog();
d.eat();
d.printInfo();
Animal c = new Cat();
c.eat();
c.printInfo();

接口

和Java一样,dart也有接口,但是和Java还是有区别的。

  • 首先,dart的接口没有interface关键字定义接口,而是普通类或抽象类都可以作为接口被实现。
  • 同样使用implements关键字进行实现。
  • 但是dart的接口有点奇怪,如果实现的类是普通类,会将普通类和抽象中的属性的方法全部需要覆写一遍。
  • 而因为抽象类可以定义抽象方法,普通类不可以,所以一般如果要实现像Java接口那样的方式,一般会使用抽象类。
  • 建议使用抽象类定义接口。
案例1
  • 定义一个Database库,支持MySQL, msSQL, MongoDB
  • MySQL, msSQL, Mongo三个类中都有同样的方法

GitHub地址:https://github.com/syh31/dart_db

案例2
  • 一个类实现多个接口
abstract class A {
  String name;
  printA();
}

abstract class B {
  int age;
  printB();
}

class C implements A,B {
  @override
  int age;

  @override
  String name;

  @override
  printA() {
    // TODO: implement printA
    print("print A");
  }

  @override
  printB() {
    // TODO: implement printB
    print("print B");
  }
  
}

void main() {
  C c = new C();
  c.printA();
  c.printB();
}

Mixins

  • Mixins的中文意思是混入,就是在类中混入其他功能。
  • 在Dart中可以使用mixins实现类似多继承的功能。

因为mixins使用的条件,随着Dart版本一直在变。

Dart2.x中使用mixins的条件:

  1. 作为mixins的类只能继承自object,不能继承其他类
  2. 作为mixins的类不能有构造函数
  3. 一个类可以mixins多个mixins类
  4. mixins绝不是继承,也不是接口,而是一种全新的特性
class Person {
  String name;
  num age;
  Person(this.name, this.age);
  printInfo() {
    print("${this.name}---${this.age}");
  }
}

class A {
  printA() {
    String info = 'This is A';
    print("Print A");
  }
  run() {
    print("A Run");
  }
}

class B {
  printB() {
    print("Print B");
  }
  run() {
    print("B Run");
  }
}

class C extends Person with A, B {
  C(String name, num age) : super(name, age);

}

void main() {
  var c = new C("张三", 20);
  c.printInfo();
  c.run();
}

输出结果:

张三—20

B Run

泛型

泛型就是解决类接口方法的复用性,以及对不特定数据类型的支持(类型校验)。

泛型方法
T getData<T>(T value) {
  return value;
}

void main() {
  print(getData(21));
  print(getData("xxx"));
  print(getData<String>("你好"));
}

输出结果:

21

xxx

你好

泛型类
List list = new List<String>();

// 错误的写法
// list.add(12);
list.add('你好');

自定义泛型类

class PrintClass<T> {
  List list = new List<T>();
  void add(T value) {
    this.list.add(value);
  }

  void printInfo() {
    for (var i = 0; i < this.list.length; i++) {
      print(this.list[i]);
    }
  }
}

void main() {
  PrintClass p1 = new PrintClass<String>();
  PrintClass p2 = new PrintClass<int>();
  p1.add("ss");
  p2.add(1);
  p2.add(5);
  p1.printInfo();
  p2.printInfo();
}

输出结果:

ss

1

5

泛型接口

泛型接口实现数据缓存的功能有:文件缓存和内存缓存。内存缓存和文件缓存按照接口约束实现。

  1. 定义一个泛型接口约束实现它的子类必须有getByKey(key)setByKey(key,value)
  2. 要求setByKey的时候的value的类型和实例化子类的时候指定的类型一致

例如,假设你创建了一个用于缓存对象的接口:

abstract class ObjectCache {
  Object getByKey(String key);
  void setByKey(String key, Object value);
}

后来发现需要一个相同功能的字符串类型接口,因此又创建了另一个接口:

abstract class StringCache {
  String getByKey(String key);
  void setByKey(String key, String value);
}

后来,又发现需要一个相同功能的数字类型接口 … 这里你应该明白了。

泛型可以省去创建所有这些接口的麻烦。 通过创建一个带有泛型参数的接口,来代替上述接口:

abstract class Cache<T> {
  T getByKey(String key);
  void setByKey(String key, T value);
}

在上面的代码中,T是一个备用类型。 这是一个类型占位符,在开发者调用该接口的时候会指定具体类型。

abstract class Cache<T> {
  getByKey(String key);
  void setByKey(String key, T value);
}

class FileCache<T> implements Cache<T> {
  @override
  getByKey(String key) {}

  @override
  void setByKey(String key, T value) {
    print("文件缓存:将数据key=${key} value=${value}写入文件中");
  }
}

class MemoryCache<T> implements Cache<T> {
  @override
  getByKey(String key) {}

  @override
  void setByKey(String key, T value) {
    print("内存缓存:将数据key=${key} value=${value}写入内存中");
  }
}

void main() {
  MemoryCache m1 = new MemoryCache<Map>();
  MemoryCache m2 = new MemoryCache<String>();
  m1.setByKey("index", {"name": "张三", "age": 32});
  m2.setByKey("home", "首页数据");
}

输出结果:

内存缓存:将数据key=index value={name: 张三, age: 32}写入内存中

内存缓存:将数据key=home value=首页数据写入内存中

在Dart中,库的使用时通过import关键字引入的。

library指令可以创建一个库,每个Dart文件都是一个库,即使没有使用library指令来指定。

Dart中的库主要有三种:

  1. 我们自定义的库

    import 'lib/xxx.dart';
    
  2. 系统内置库

    import 'dart:math';
    import 'dart:io';
    import 'dart:convert';
    
  3. Pub包管理系统中的库
    https://pub.dev/packages
    https://pub.flutter-io.cn/packages
    https://pub.dartlang.org/flutter/

    1. 需要在自己想项目根目录新建一个pubspec.yaml
    2. pubspec.yaml文件然后配置名称、描述、依赖等信息
    3. 然后运行pub get/flutter pub get获取包下载到本地
    4. 项目中引入库 import 'package:http/http.dart' as http;,看文档使用
系统内置库

pubspec.yaml

name: xxx
description: A Dart pub
dependencies:
  http: ^0.12.2

index.dart

import 'dart:io';
import 'dart:convert';

void main() async {
  var result = await _getDataFromZhihuAPI();
  print(result);
}

// API接口:http://news-at.zhihu.com/api/3/stories/latest
_getDataFromZhihuAPI() async {
  // io库中提供的HttpClient对象
  // 1、创建HttpClient对象
  var httpclient = new HttpClient();
  // 2、创建Uri对象
  var uri = new Uri.http("news-at.zhihu.com", "api/3/stories/latest");
  // 3、发起请求,等待请求
  var request = await httpclient.getUrl(uri);
  // 4、关闭请求,等待响应
  var response = await request.close();
  // convert库中的编码转换方法
  // 5、解码响应的内容
  return await response.transform(utf8.decoder).join();
}
Pub包管理系统

以http包为例:https://pub.dev/packages/http/

import 'dart:convert' as convert;
import 'package:http/http.dart' as http;

void main(List<String> arguments) async {
  // 接口地址
  var url = 'http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=1';

  // Await the http get response, then decode the json-formatted response.
  var response = await http.get(url);
  if (response.statusCode == 200) {
    var jsonResponse = convert.jsonDecode(response.body);
    print(jsonResponse);
  } else {
    print('Request failed with status: ${response.statusCode}.');
  }
}

当引入两个库中有相同名称标识符的时候,可以使用as来对库进行重命名

import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;

Element element1 = new Element();  //Uses Element from lib1.
lib2.Element element2 = new lib2.Element();  // Uses Element from lib2.
部分导入

如果只需要导入库的一部分,有两种模式:

  1. 只导入需要的部分,使用show关键字,如下例子所示:

    import 'package:lib1/lib1.dart' show foo;
    
  2. 隐藏不需要的部分,使用hide关键字,如下例子所示:

    import 'package:lib2/lib2.dart' hide foo;
    
异步支持

使用 asyncawait 关键字实现异步编程。 可以让你像编写同步代码一样实现异步操作。

这两个关键字的使用只需要记住两点:

  • 只有async方法才能使用await关键字调用方法
  • 如果调用别的async方法必须使用await关键字

async是让方法变成异步。

await是等待异步方法执行完成。

void main() async {
  var result = await testAsync();
  print(result);
}

testAsync() async {
  return "Hello Async";
}
懒加载

懒加载也称为延迟加载,可以在需要的时候再进行加载。懒加载的最大好处是可以减少APP的启动时间。

懒加载使用deferred as关键字来指定,如下例子所示:

import 'package:deferred/hello.dart' deferred as hello;

当需要使用的时候,需要使用loadLibrary()方法来加载:

greet() async {
  await hello.loadLibrary();
  hello.printGreeting();
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值