Hellom's Studio.

Dart 学习之面向对象编程1

字数统计: 1.4k阅读时长: 6 min
2019/07/16 Share

类与对象

  • 使用 class 声明一个类

  • 使用关键字 new 创建一个对象 new可省略

  • 所有对象都继承于 Object

属性与方法

  • 属性会默认生成 gettersetter 方法

  • 使用 final 声明的属性只有getter(只读)

  • 属性和方法通过 . 访问

  • 方法不能被重载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
e.g.

void main() {
var person = Person();

//属性和方法通过 `.` 访问
person.age = 20;
person.name = 'Tom';
}

class Person{
String name;
int age;

void work(){
print('Name is $name , age is $age , she is working...');
}

//error 方法不能被重载
void work(){
print('work...');
}
}

类及成员可见性

  • Dart 中的可见性以 library (库)为单位

  • 默认情况下 每个 Dart 文件就是一个库

  • 使用 import导入库

  • 使用 _ 表示库的私有性


计算属性

  • 顾名思义,计算属性的值是通过计算而来,本身不存储值

  • 计算属性赋值,其实是通过计算转换到其它实例变量

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
e.g.

void main() {
var rect = Rectangle();

rect.width = 20;
rect.height = 10;

print(rect.area); // 200

rect.area = 200;

print(rect.area); // 100.0
}

class Rectangle {
num width;
num height;

num get area => width * height; //计算属性

set area(value) {
width = value / 20;
}
}

构造方法

  • 如果没有自定义构造方法,则会有个默认的构造方法

  • 如果存在自定义构造方法,则默认构造方法无效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
e.g.

void main() {
var person = Person('Tom', 20);
}

class Person {
String name;
int age;
final String gender;

//自定义构造方法 替代了 默认构造方法
Person(String name, int age) {
this.name = name;
this.age = age;
}

void work() {
print('Name is $name , age is $age , she is working...');
}
}

其中自定义构造方法 可使用语法糖 改写成如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Person {
String name;
int age;
final String gender;

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

// after
Person(this.name, this.age);
}

利用语法糖可以对以 final 声明的值 赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Person {
String name;
int age;
final String gender;

// before
Person(String name, int age,String gender) {
this.name = name;
this.age = age;
this.gender = gender; // error 这边赋值就报错了
}

// after
Person(this.name, this.age, this.gander); // gotcha 可赋值
  • 构造方法不能重载

如果要在一个类里面 添加多个构造方法怎么办呢?

这就要用到命名构造方法啦

命名构造方法

  • 使用命名构造方法,可以实现多个构造方法

  • 使用 类名.方法的形式实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
e.g.

void main() {
var person = Person('Tom', 20, 'male');
var person = Person.withName('May');
}

class Person {
String name;
int age;
final String gander;

Person(this.name, this.age,this.gander);

Person.withName(this.name); // 多个构造方法

void work() {
print('Name is $name , age is $age , she is working...');
}
}

常量构造方法

  • 如果类是不可变状态,可以把对象定义为编译时常量

  • 使用 const 声明构造方法,并且所有的变量都为 final

  • 使用 const 声明对象,可省略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
e.g.

void main() {
const person = const Person('Tom', 20, 'male');
}

class Person {
final String name;
final int age;
final String gander;

const Person(this.name, this.age, this.gander);

void work() {
print('Name is $name , age is $age , she is working...');
}
}

工厂构造方法

  • 工厂构造方法类似于设计模式的工厂模式

  • 在构造方法前添加关键字 factory 实现一个工厂构造方法

  • 在工厂构造方法中可返回对象


初始化列表

  • 初始化列表会在构造方法体执行之前执行

  • 使用逗号分隔初始化表达式

  • 初始化列表常用于设置 final 变量的值

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
e.g.

void main() {
var person = Person('Tom', 20, 'male');
}

class Person {
String name;
int age;
final String gander;

Person(this.name, this.age, this.gander);

//: gander = map['gander'] 给final 赋值的方法
Person.withMap(Map map) : gander = map['gander'] {
this.name = map['name'];
this.age = map['age'];
}

//也可简写成以下形式
Person.withMap2(Map map): gander = map['gander'],name = map['name'] {
age = map['age']
}

void work() {
print('Name is $name , age is $age , she is working...');
}
}

静态成员

  • 使用 static 关键字来实现类级别的变量和函数

  • 静态成员不能访问非静态成员,非静态成员可以访问静态成员

  • 类中的常量需要使用 static const 声明

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
e.g.

void main() {
var page = Page();

page.scrollDown(); // error 不可访问类级别的方法

Page.scrollDown(); // right
}

class Page {
static const int currentPage = 1;

//下拉
static void scrollDown() {
currentPage = 1;
print('scrollDown...');
}

// 上拉
void scrollUp() {
currentPage++;
print('scrollDown...');
}
}

对象操作符

  • 条件访问 ?.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
e.g.

void main() {
Person person;

person.work(); // error 不能对空值的变量调用方法

person?.work(); // right 判断是否有值 有值就继续走下去
}

class Person {
String name;
int age;

void work() {
print('working...');
}
}
  • 类型转换 as
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
e.g.

void main() {
var person;

person = '';

person = new Person();

person.work(); //error 不确定是什么类型

(person as Person).work(); // right
}

class Person {
String name;
int age;

void work() {
print('working...');
}
}
  • 是否制定类型:is,is!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
e.g.

void main() {
var person;

person = '';

person = new Person();

if (person is Person) {
person.work(); // right
}
}

class Person {
String name;
int age;

void work() {
print('working...');
}
}
  • 级联操作:..
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
e.g.

void main() {
var person = new Person();

//.. 相当于 build 模式
person..name = 'May'
..age = 20
..work();
}

//也可简写成以下模式
new Person()
..name = 'May'
..age = 20
..work();


class Person {
String name;
int age;

void work() {
print('working...');
}
}

对象 call 方法

  • 如果类实现了 call() 方法,则该类的对象可以作为方法使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
e.g.

void main() {
var person = new Person();

person('Tom', 20);
}

class Person {
String name;
int age;

String call(String name, int age) {
return 'Name is $name , age is $age';
}
}

可以了解下 call 方法 实际项目中不建议使用

CATALOG
  1. 1. 类与对象
    1. 1.1. 属性与方法
    2. 1.2. 类及成员可见性
  2. 2. 计算属性
  3. 3. 构造方法
    1. 3.1. 命名构造方法
  4. 4. 常量构造方法
  5. 5. 工厂构造方法
  6. 6. 初始化列表
  7. 7. 静态成员
  8. 8. 对象操作符
  9. 9. 对象 call 方法