Dart语言快速入门:类和对象、工厂方法接口...
类和对象
类的定义
// Dart中定义一个类
class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
}
复制代码
Dart中的类与Java中的相似,不同的是,Dart中没有private
、public
这些成员访问修饰符。如果是类私有的成员,不希望外面访问,只需要在成员变量之前加上一个下划线_
变为私有即可。
以上代码,在Dart中还有一种简化写法,可以自动在构造方法中对成员变量初始化。
// Dart中定义一个类
class Person {
String name;
int age;
// 在构造方法中初始化成员变量时,可使用如下写法简化
Person(this.name, this.age);
// 如需处理其他变量时,也可单独对其操作
// Person(this.name, this.age, String address){
// print(address);
// }
// 注意,构造方法不能重载,以上注释掉
}
复制代码
另外还需要注意一点,Dart中没有构造方法的重载,不能写两个同名的构造方法。
Getters 和 Setters方法
在Java中,一般不会直接在类的外部去访问类成员,通常使用setter和getter方法来操作类的成员变量。而在Dart语言中,所有类中都包含隐式的getter方法,对于非final
修饰的成员,类中还包含隐式的setter方法。这就意味着,在Dart中,你可以直接在类外部通过.
操作符访问类成员。这一特点使得Dart语法更加简洁,不会写出满屏的setXXX、getXXX方法。
当然,很多时候我们调用setter和getter方法并不仅仅是为了赋值和访问,而是为了一些额外的处理,这时候我们只需要使用set
与get
关键字实现setter和getter方法即可。
class Person {
String userName;
Person(this.userName);
// 方法名前加get关键字
String get name{
return "user:" + this.userName;
}
// 方法名前加set关键字
set name(String name){
// do something
this.userName = name;
}
}
void main() {
var p = new Person("zhangsan");
print(p.name); // user:zhangsan
p.name = "Jack";
print(p.name); // user:Jack
}
复制代码
要注意,在创建对象时,new
关键字并不是必须的,可以省略不写。在写Flutter界面时,不建议写new
关键字实例化对象,因为Flutter框架中没有类似的xml语言来描述UI界面,界面也是使用Dart语言来写,在使用Dart写UI时,要保持代码的简洁和结构化,省略new
会更友好。
构造方法
如果没有定义构造方法,则会有一个默认的无参构造方法,并且会调用超类的无参构造方法。
命名构造方法
上面已经说过,Dart类中两个同名构造方法不能重载,但是Dart语言为类新增了一种称为命名构造方法
的东西。
class Person {
String userName;
int age;
Person(this.userName, this.age);
// 命名构造方法
Person.fromData(Map data) {
this.userName = data['name'];
this.age = data['age'];
}
}
void main() {
// 使用命名构造方法创建对象
var p = new Person.fromData({
"name":"Bob",
"age":19
});
print(p.userName);
}
复制代码
注意,使用命名构造方法可以为一个类实现多个构造方法,也可以更清晰的表明意图。
常量构造方法
如果想提供一个状态永远不变的对像,在Dart中,我们可以创建一个编译时常量对象,节省开销。
class ConstPoint {
final num x;
final num y;
// 使用const修构造方法
const ConstPoint(this.x, this.y);
// 编译时常量对象,需使用const来创建对象
static final ConstPoint origin = const ConstPoint(0, 0);
}
void main() {
print(ConstPoint.origin.x);
print(ConstPoint.origin.y);
}
复制代码
工厂构造方法
当我们需要创建一个新的对象或者从缓存中取一个对象时,工厂构造方法就派上了用场。
class Logger {
final String name;
// 创建一个静态Map做为缓存
static final Map _cache = {};
// 定义一个命名构造方法,用下划线"_"修饰,将构造方法私有化
Logger._internal(this.name);
// 使用关键字factory修饰类同名构造方法
factory Logger(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
// 调用命名构造方法创建新对象
final logger= new Logger._internal(name);
_cache[name] = logger; // 存入缓存
return logger;
}
}
}
void main() {
var uiLog = new Logger('UI');
var eventLog = new Logger('event');
}
复制代码
构造方法重定向
有时候一个构造方法会调动类中的其他构造方法来实例化,这时候可以使用构造方法重定向,
class Point {
num x;
num y;
// 同名构造方法
Point(this.x, this.y);
// 命名构造方法重定向到同名构造方法,中间使用一个冒号
Point.alongXAxis(num x) : this(x, 0);
}
复制代码
类的初始化列表
熟悉C++的朋友应该对初始化列表很了解了,Java中是没有这个特性的。
class Point {
final num x;
final num y;
final num distance;
Point(x, y)
: x = x,
y = y,
distance = sqrt(x * x + y * y){
print("这是构造方法");
}
}
void main() {
var p = new Point(2, 3);
print(p.distance);
}
复制代码
- 初始化列表位于构造方法的小括号与大括号之间,在初始化列表之前需添加一个冒号。
- 初始化列表是由逗号分隔的一些赋值语句组成。
- 它适合用来初始化
final
修饰的变量 - 初始化列表的调用是在构造方法之前,也就是在类完成实例化之前,因此初始化列表中是不能访问
this
的 - 使用 Future API