Dart 面向对象的程序设计
发表于 2019-07-10 12:38
|
分类于 Dart
|
评论次数 0
|
阅读次数 52

面向对象的语言有一个标志,那就是它们都有类的概念,而通过类可以创建任意多个具有相同属性和方法的对象。

Dart 也是面向对象的语言,同时支持 mixin 的继承机制。Dart 的每个对象都是一个类的实例,所有的类都继承于 Object 类,基于 mixin 的继承意味着每个类( Object 类除外)只有一个超类(父类),一个类的代码可以在其他多个子类中使用,有过编程经验的人一般都知道这个概念,所以我就不再赘述。

创建类

和大多数语言一样,使用 class 关键字作为前缀创建一个类,使用 extends 继承另外一个类:

class Bar { } class Foo extends Bar { }

构造函数

Dart 的构造函数和 PHP 5 一样,在类中声明一个与类名相同的函数就可以创建一个构造函数。

如果不主动声明构造函数,系统将提供一个默认的构造函数,默认的构造函数是没有名字、没有参数的,并且在被实例化时,系统将自动调用父类的无参数构造函数(若参数都是可选参数,也会被自动调用)。

下面的例子在 Person 类中主动声明了一个构造函数,并初始化 sexage 属性的值:

class Person { String sex; int age; Person({sex: 'girl', age: 18}) { this.sex = sex; this.age = age; } }

上面的代码中 this 指向 Person 实例,使用 this 关键字可以访问 Person 类中的属性和方法。

由于将构造函数的参数赋值给属性这种写法非常频繁,所以 Dart 提供了语法糖,让我们可以更简洁地实现上面的功能:

class Person { String sex; int age; Person({this.sex: 'girl', this.age: 18}); }

理解对象

使用 new 关键字和构造函数可以创建新的对象:

main() { final leo = new Person(); print(leo);// output: Instance of 'Person' }

Dart 2 版本以后,可以省略构造函数之前的关键字 new,所以说下面这种写法是和上面的代码等价的:

main() { final leo = Person(); print(leo);// output: Instance of 'Person' }

使用 . 操作符来访问对象的方法或属性:

main() { final leo = Person(sex: 'boy', age: 22); print(leo);// output: Instance of 'Person' print(leo.sex);// output: boy print(leo.age);// output: 22 }

上面的代码中,如果变量 foo 的值为 null,那么使用 foo.pi 访问属性将会报错,而使用 ?. 操作符就可以避免这个问题:

main() { var foo; print(foo?.pi);// output: null }

命名构造函数

通过命名构造函数可以让一个类拥有多个构造函数,提供更有针对性的构造函数。

命名构造函数的命名格式为 ClassName.identifier,用法如下:

class Person { String sex; int age; Person({this.sex: 'girl', this.age: 18}); Person.baby({this.sex: 'girl', this.age: 3}); }

上面的代码中,Person 类提供了 baby 命名构造函数,我们使用 Person.baby() 即可创建一个新的实例:

main() { final baby = Person.baby(); print(baby.sex);// output: girl print(baby.age);// output: 3 }

调用超类构造函数

子类不会继承超类的构造函数,默认情况下,子类的构造函数会在执行之前自动调用超类的无参数构造函数(若超类的构造函数都是可选参数,也会被子类自动调用)。

超类若定义了必须传递参数的构造函数,子类的构造函数则不会自动调用超类的构造函数,并且子类必须手动调用超类的构造函数。

例如下面的代码中, Person 类声明了 2 个构造函数,第一个构造函数规定必须传递 2 个参数:

class Person { final sex; final age; Person(this.sex, this.age); Person.baby({this.sex: 'girl', this.age: 3}); }

接着,再定义一个 Employee 类,继承 Person 类,此时 Employee 类就必须手动调用 Person 构造函数。使用 : 操作符和 super 关键字即可进行手动调用:

class Employee extends Person { final name; final salary; Employee({this.name: 'leo', this.salary: 3000}) : super('girl', 18); } main() { final people = Employee(); print(people.name);// output: leo print(people.salary);// output: 3000 print(people.sex);// output: girl print(people.age);// output: 18 }

如果想调用 Person 类的 baby 命名构造函数,使用 super.baby() 即可调用:

class Employee extends Person { final name; final salary; Employee({this.name: 'leo', this.salary: 3000}) : super.baby(); } main() { final people = Employee(); print(people.name);// output: leo print(people.salary);// output: 3000 print(people.sex);// output: girl print(people.age);// output: 3 }

initialize list(初始化参数列表)

构造函数后的 : 后面,除了可以使用 super 关键字调用超类的构造函数,还可以初始化实例参数。

多个表达式使用 , 分隔即可,这些表达式被称之为初始化参数列表,下面是使用示例:

class Person { final sex; final age; Person(this.sex, this.age); Person.baby({this.sex: 'girl', this.age: 3}); } class Employee extends Person { final name; final salary; final position; Employee(Map people) : name = people['name'], salary = people['salary'], position = people['position'], super.baby(); } main() { final people = Employee({ 'name': 'leo', 'salary': 3000, 'position': 'php' }); print(people.name);// output: leo print(people.salary);// output: 3000 print(people.position);// output: php print(people.sex);// output: girl print(people.age);// output: 3 }

如果在初始化参数列表中使用 super 关键字调用父类的构造函数,推荐将它放到列表的最后,详情参考 Dart 最佳实践

构造函数执行顺序

如果提供了初始化参数列表,则初始化参数列表会在超类构造函数执行之前被调用,下面是构造函数的执行顺序:

(1)initialize list(初始化参数列表)

(2)super class’s no-arg constructor(超类的无参数构造函数)

(3)main class’s no-arg constructor(主类的无参数构造函数)

重定向构造函数

顾名思义,即调用该构造函数会重定向到其他构造函数。重定向函数是没有代码的,使用 :this 调用其他构造函数:

发布评论
还没有评论,快来抢沙发吧!