# 12.类

# 面向对象的介绍

/**
 * 面向对象编程(OOP)的三个基本特征是: 封装, 继承, 多态
 *      封装: 封装是对象和类概念的主要特性. 封装, 把客观事物封装成抽象的类, 并且把自己的部分属性和方法提供给其他对象
 *      
 *      继承: 面向对象编程(OOP) 语言的一个主要功能就是 '继承', 继承是指这样一种能力: 它可以使用现有类的功能, 并拥有父类的功能
 * 
 *      多态: 允许将子类的指针赋值给父类类型的指针, 同一个函数调用会有不同的执行效果.
 * 
 * Dart所有的东西都是对象, 所有的对象都继承自Object类
 * Dart是一门使用类和单继承的面向对象语言, 所有的对象都是类的实例, 并且所有的类都是Object的子类
 * 一个类通常由属性和方法组成
 */
1
2
3
4
5
6
7
8
9
10
11
12

# 类的创建

/**
 * Dart是一门使用类和单继承的面向对象语言, 所有的对象都是类的实例, 并且所有的类都是Object的子类
 */

class Person {
  String name="张三";
  int age=23;

  void getInfo() {
    // print("$name---$age");
    print("${this.name}---${this.age}");
  }
}

void main() {
  // 实例化
  var p1 = new Person();
  print(p1.name);
  p1.getInfo();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 构造函数

class Person {
  String name;
  int age;

  // 默认构造函数
  // Person(String name, int age) {
  //   this.name = name;
  //   this.age = age;
  // }

  // 默认构造函数的简写
  Person(this.name, this.age);

  void printInfo() {
    print("${this.name}---${this.age}");
  }
}

void main() {
  // 实例化
  Person p1 = new Person('张三', 20);
  Person p2 = new Person('李四', 21);
  p1.printInfo();
  p2.printInfo();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 命名构造函数

/**
 * 构造函数可以写多个
 */
class Person {
  String name;
  int age;

  // 默认构造函数的简写
  Person(this.name, this.age);
  
  // 命名构造函数
  Person.now() {
    print('我是命名构造函数');
  }

  void printInfo() {
    print("${this.name}---${this.age}");
  }
}


void main() {
  // var d = new DateTime.now();  // 实例化DateTime调用它的命名构造函数
  // print(d);

  Person p1 = new Person('张三',20); // 默认实例化类的时候调用的是 默认构造函数'
  Person p2 = new Person.now(); 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 类模块化

# 1).lib/Person.dart

class Person {
  String name;
  int age;

  // 默认构造函数的简写
  Person(this.name, this.age);

  Person.now(String name, int age) {
    print('我是命名构造函数');
  }

  Person.setInfo(String name, int age) {
    this.name = name;
    this.age = age;
  }

  void printInfo() {
    print("${this.name}---${this.age}");
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 2).main

import 'lib/Person.dart';

void main() {
  Person p1 = new Person.setInfo('张三', 20);
  p1.printInfo();
}
1
2
3
4
5
6

# 私有属性/私有方法

# 1).lib/Animal.dart

class Animal {
  String _name;
  int age;

  // 默认构造函数的简写
  Animal(this._name, this.age);

  
  String getName() {
    return this._name;
  }

  void _run() {
    print('这是一个私有方法');
  }

  execRun() {
    this._run();  // 类里面的方法相互调用
  }

  void printInfo() {
    print("${this._name}---${this.age}");
  }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 2).main

/**
 * Dart和其他面向对象语言不一样, Dart中没有 public  private protected 这些访问修饰符
 * 
 * 但是我们使用_把一个属性或者方法定义成私有
 */

import 'lib/Animal.dart';

void main() {
  Animal a = new Animal('小狗', 3);
  print(a.getName());  // 间接的访问私有属性
  a.execRun();  // 间接的调用私有方法
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# getter和setter修饰符

class Rect {
  num height;
  num width;

  Rect(this.height, this.width);

  // get 方法
  get area {
    return this.height*this.width;
  }

  // set 方法
  set areaHeight(value) {
    this.height = value;
  }
}

void main() {
  Rect r = new Rect(10, 4);
  r.areaHeight = 6;
  print('矩形面积:${r.area}');  // 注意调用直接通过访问属性的方式访问area
}s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 初始化列表

// Dart中我们也可以在构造函数体运行之前初始化实例变量

class Rect{
  int height;
  int width;

  Rect():height=2,width=10 {}

  getArea() {
    return this.height*this.width;
  }
}

void main() {
  Rect r = new Rect();
  print(r.getArea());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 静态成员/静态方法

/**
 * Dart中的静态成员
 * 
 *  1.使用static  关键字来实现类级别的变量和函数
 *  2.静态方法不能访问非静态成员, 非静态方法可以访问静态成员
 */

class Person {
  static String name="张三";
  int age = 20;

  static void show() {
    print(name);
  }
  void printInfo() {  /**非静态方法可以访问静态成员以及非静态成员 */
    print(name);     // 访问静态属性
    print(this.age); // 访问非静态属性

    show();  // 调用静态方法
  }
  static void printUserInfo() {
    print(name);   // 静态属性
    show();        // 静态方法
  }
}

main() {
  // print(Person.name);
  // Person.show();

  Person p = new Person();
  p.printInfo();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 操作符

/**
 * Dart中的对象操作符
 * 
 *  ?   条件运算符  (了解)
 *  as  类型转换 
 *  is  类型判断
 *  ..  级联操作 (连缀)  (记住)
 */

class Person {
  String name;
  num age;
  Person(this.name, this.age);
  void printInfo() {
    print('${this.name}---${this.age}');
  }
}

main() {
  Person p = new Person('张三', 20);

  // ?  is
  if(p is Person) {
    p.name='李四';
  }

  p?.printInfo();     // 李四---20

  print(p is Object); // true

  // as
  var p1;
  p1='';
  p1 = new Person('张三',20);
  (p1 as Person).printInfo();  // 张三---20

  // .. 级联操作
  Person p2 = new Person('张三1', 20);

  p2..name='李四'
    ..age=30
    ..printInfo();  // 李四---30
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

# 类的继承

# 1).简单继承

/**
 * 面向对象的三大特性: 封装, 继承, 多态
 * 
 * Dart中的类的继承:
 *    1.子类使用extends关键词来继承父类
 *    2.子类会继承父类里面可见的属性和方法, 但是不会继承构造函数
 *    3.子类能覆写父类的方法 getter和setter
 */

class Person {
  String name="张三";
  num age=20;
  void printInfo() {
    print('${this.name}--${this.age}');
  }
}

class Web extends Person {}

main() {
  Web w = new Web();
  print(w.name);   // 张三
  w.printInfo();   // 张三--20
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 2).super关键词的使用

/**
 * 面向对象的三大特性: 封装, 继承, 多态
 * 
 * Dart中的类的继承:
 *    1.子类使用extends关键词来继承父类
 *    2.子类会继承父类里面可见的属性和方法, 但是不会继承构造函数
 *    3.子类能覆写父类的方法 getter和setter
 */

class Person {
  String name;
  num age;
  Person(this.name, this.age);
  void printInfo() {
    print('${this.name}--${this.age}');
  }
}

class Web extends Person {
  String sex;
  Web(String name, num age, String sex): super(name, age){
    this.sex = sex;
  }
  run() {
    print('${this.name}--${this.age}--${this.sex}');
  }
}

main() {
  Web w = new Web('张三', 12, '男');
  w.printInfo();   // 张三--12
  w.run();         // 张三--12--男
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 3).覆写父类的方法

/**
 * 面向对象的三大特性: 封装, 继承, 多态
 * 
 * Dart中的类的继承:
 *    1.子类使用extends关键词来继承父类
 *    2.子类会继承父类里面可见的属性和方法, 但是不会继承构造函数
 *    3.子类能覆写父类的方法 getter和setter
 */

class Person {
  String name;
  num age;
  Person(this.name, this.age);
  void printInfo() {
    print('${this.name}--${this.age}');
  }
  work() {
    print('${this.name}在工作...');
  }
}

class Web extends Person {
  Web(String name, num age): super(name, age);

  // 覆写父类的方法
  // override注解是为了检查父类是否有这个方法供你重写
    // 可写可不写  建议在覆写父类方法的时候加上
  void printInfo() {
    print('姓名:${this.name}--年龄:${this.age}');
  }
}

main() {
  Web w = new Web('星城',20);
  w.printInfo();   // 姓名:星城--年龄:20
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# 抽象类

/**
 * 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 {  
  
  eat() {    // 子类继承抽象类必须得实现里面的抽象方法
    print('小狗在吃骨头');
  }
}

main() {
  Dog d = new Dog();
  d.eat();
  d.printInfo();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# 多态

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

abstract class Animal{
  eat();  // 抽象方法
}

class Dog extends Animal {  
  
  eat() {    // 子类继承抽象类必须得实现里面的抽象方法
    print('小狗在吃骨头');
  }
}

class Cat extends Animal {
  
  eat() {    // 子类继承抽象类必须得实现里面的抽象方法
    print('小猫在吃鱼');
  }
}

main() {
  Dog d = new Dog();
  d.eat();

  Cat c = new Cat();
  c.eat();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 接口

/**
 * 和Java一样, dart也有接口, 但是和Java还是有区别的
 * 
 * 首先, dart的接口没有interface关键字定义接口, 而是普通类或抽象类都可以作为接口被实现
 * 同样使用implements关键字进行实现
 * 
 * 但是dart的接口有点奇怪, 如果实现的类是普通类, 会将普通类和抽象中的属性的方法全部需要覆写一遍
 * 
 * 而因为抽象类可以定义抽象方法, 普通类不可以, 所以一般如果要实现像Java接口那样的方式, 一般会使用抽象类.
 * 
 * 建议使用抽象类定义接口
 * 
 * 需求:
 *    定义一个DB库, 支持 mysql  mssql  mongodb
 *    mysql  mssql mongodb三个类里面都有同样的方法
 */

abstract class Db {  // 当做接口  接口: 就是约定, 规范
  String uri;  // 数据库的连接地址
  add(String data);
  save();
  delete();
}

class Mysql implements Db {
  
  String uri;

  Mysql(this.uri);

  
  add(String data) {
    print('这是mysql的add方法: '+data);
  }

  
  delete() {
    // TODO: implement delete
    throw UnimplementedError();
  }

  
  save() {
    // TODO: implement save
    throw UnimplementedError();
  }
  
}

class MsSql implements Db {
  
  String uri;

  
  add(String data) {
    // TODO: implement add
    throw UnimplementedError();
  }

  
  delete() {
    // TODO: implement delete
    throw UnimplementedError();
  }

  
  save() {
    // TODO: implement save
    throw UnimplementedError();
  }
  
}

main() {
  Mysql mysql = new Mysql('xxxxx');
  mysql.add('星城哈哈');
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

# 一个类实现多个接口

/**
 * Dart中一个类实现多个接口
 */

abstract class A {
  String name;
  printA();
}

abstract class B {
  String name;
  printB();
}

class C implements A,B {
  
  String name;

  
  printA() {
    print('我是a');
  }

  
  printB() {
    print('我是b');
  }
  
}

main() {
  C c = new C();
  c.printA();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# mixins

/**
 * mixins的中文意思是混入, 就是在类中混入其他功能
 * 
 * 在Dart中可以使用mixins实现类似多继承的功能
 * 
 * 因为mixins使用的条件, 随着Dart版本一直在变, 这里讲的是Dart2.x中使用mixins的条件;
 * 
 *  1.作为mixins的类只能继承自Object, 不能继承其他类
 *  2.作为mixins的类不能有构造函数
 *  3.一个类可以mixins多个mixins类
 *  4.mixins绝不是继承, 也不是接口, 而是一种全新的特性
 */

class A {
  String info='this is A';
  void printA() {
    print('A');
  }
}

class B {
  void printB() {
    print('B');
  }
}

class C with A,B {

}

void main() {
  var c = new C();
  c.printA();
  c.printB();
  print(c.info);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# mixins的类型

/**
 *  mixins的实例类型是什么?
 * 
 *  很简单, mixins的类型就是其超类的子类型
 */

class A {
  String info='this is A';
  void printA() {
    print('A');
  }
}

class B {
  void printB() {
    print('B');
  }
}

class C with A,B {

}

void main() {
  var c = new C();
  print(c is A);  // true
  print(c is B);  // true
  print(c is C);  // true
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
上次更新: 2021/2/21 下午7:52:17