类
类是所有面向对象语言最重要的一个环节。首先需要对 Dart 的类进行一个比较全面的认知,才有助于我们学习和理解其中一些功能的设计:Dart 中的类是 单继承,且没有 方法重载 的
创建一个类
-
方法 / 属性
创建一个类,和java很像,定义属性,定义构造函数,在定义一些方法。实例化的时候,new也不用写,直接按照构造参数传参,一个Rect实例就诞生了。class Rect{ int width = 0; int height = 0; Rect(int width,int height){ this.width = width; this.height = height; } int area()=>width * height; } var rect = Rect(10, 12); print(rect.area()); -
静态方法和属性
静态方法和属性很简单,加上static之后即可。class Rect{ int width = 0; int height = 0; static demo = 10; Rect(int width,int height){ this.width = width; this.height = height; } int area()=>width * height; static Area(int width, int height) => width * height; } -
get and set
和java不一样,我们默认的属性就能给外界访问,因此不需要写繁琐的get和set方法。但是,如果你希望监听属性变化,get和set不失为一个很好的方案。class Rect{ int width = 0; int height = 0; set setWidth(int width) { this.width = width; } int get getWidh { return this.width; } }
构造函数
-
初始化列表
大家都知道构造函数传递的参数一般都是给特定的属性的,因此,如果你在构造函数中没有其他的事情做,Dart是提供了一个简化的写法: 初始化列表
除了能简化构造函数的写法,它也能在构造函数的时候给一个final的属性赋值。final的值只能赋值一次。因此传统写法会报错:构造函数函数体执行的时候,这些属性已经给创建了。// 繁琐的传统写法 class Rect{ final int width; // final 的值只能赋值一次。因此传统写法会报错。 int height = 0; Rect(int width,int height){ this.width = width; this.height = height; } } // 简化写法 class Rect{ int width = 0; int height = 0; Rect(this.width,this.height); } // ru1 -
命名构造函数
由于Dart是没有方法重载的。但是不同的构造函数来创建类是实际开发必须的。因此有了这个: 命名构造函数
个人认为, 命名构造函数 + 函数的命名参数 简直就是object-c的常规函数写法。虽然有点繁琐。但是在阅读代码的时候,能让人非常清晰,一读就通。
同时也可以通过 重定向构造函数 来简化我们的 命名构造函数class Rect{ int width = 0; int height = 0; Rect(this.width,this.height); // 命名构造函数 //Rect.fromJson(Map json){ // this.width = json["width"]; // this.width = json["height"]; //} // 重定向构造函数 简化赋值过程 Rect.fromJson(Map json) : this(json["width"], json["height"]); } var rect = Rect.fromJson({"width": 1, "height": 2}); -
工厂构造方法
如果我们希望创建一个单例对象的时候,我们希望这个类在任何时候都能返回第一次创建的对象,因此我们就需要控制构造函数返回的对象,而在上面介绍的构造方法里面,我们都无法控制返回的对象,因此 工厂构造方法 就诞生了。class Singleton { static Singleton instance; Singleton() {} factory Singleton.shareInstance() { if (instance != null) { instance = Singleton(); } return instance; } }
继承 (extends)
使用 extends 我们能把一个类的所有属性和方法都放进一个新的类里面,除了能在新的类加上自己特有的方法,还能通过 super 访问父类的方法,通过 @override 改写父类的方法。
class Animal {
String name;
Animal(this.name);
void say() {
print(this.name);
}
}
class Cat extends Animal {
Cat(String name) : super(name);
@override
void say() {
print("my name is " + this.name);
}
}
抽象类
由 abstract 定义的都是抽象类,而抽象类中,有只存在名字,而没有内容的方法,这种叫做抽象方法。
- 抽象类无法实例化
- 继承抽象类的子类必须把抽象类中的抽象方法给实现了。
- 抽象类已经实现的方法不能通过
@override修改了。
abstract class Animal {
String name;
Animal(this.name);
void eat();
void say() {
print(this.name);
}
}
class Cat extends Animal {
Cat(String name) : super(name);
@override
void eat() {
print(this.name + " eat fish");
}
}
接口 (implements)
在 dart 中,所有的类都是接口。因此我们可以直接 implements 所有的类,和 extends 不一样,一旦 implements 了指定的类之后,必须把它的方法都实现一遍,而且不能调用 super。因为 super 是属于父类的。
由于很多时候我们使用接口都只是约定一个规范,让我们去调用指定的接口方法。因此在 dart 一般都是使用 抽象类 来做接口。这样就不要把实现了一遍的方法又实现一遍。
class Animal {
String name;
Animal(this.name);
void say() {
print(this.name);
}
}
class Action {
void eat() {
print("eat");
}
}
class Cat extends Animal implements Action {
Cat(String name) : super(name);
@override
void say() {
print("my name is " + this.name);
}
@override
void eat() {
print(this.name + " eat");
}
}
混合 (mixin)
implements 其实只是使用了一个类的躯壳,每一个方法在新的类上都需要重新实现一遍,不能像 extends 能直接使用,但是 extends 只能是单继承。因此 混合 这个新的特性就在 dart 诞生了。
class Animal {
String name;
Animal(this.name);
void say() {
print(this.name);
}
}
class Action {
String action;
void doSomeThing() {
print(this.action);
}
}
class Cat extends Animal with Action {
Cat(String name) : super(name);
@override
void say() {
print("my name is " + this.name);
}
}
main(List<String> args) {
var cat = Cat('cat');
cat.say();
cat.action = "eat";
cat.doSomeThing();
}
继承,混合,接口的区别
在刚使用 dart 的时候,最大的困惑就是:with, extends 和 implements 的区别。
- 从思想层面上说:
extends是面向对象的常用做法,主要是为了把同类事物的特性提取出来,从而达到代码的复用,with的思想主要是组合,不仅仅是同类的事物有这些特性,我们可以把不同类的事物的相同逻辑提取出来使用。implements的思想就是约定,每一个接口就是一个个约定和规则,我们根据这些规则去实现自己的方法。
- 从使用层面来说
extends和一般的继承一样,把方法,属性都给新的类,新的类可以访问回去父类,可以选择是否改写父类的东西。继承之后,两个还是关联的with和继承很像,只是优先级永远低于继承:同名方法和属性,都以继承为准implements其实就是无论 implements 了什么类,你都可以把这个类当成抽象类,因为你得把它的方法都实现一遍