文章

Dart:为Java开发人员准备的Dart教程

以下内容来自Flutter官方的“为Java开发人员准备的Dart教程”中记录的笔记。

一、创建一个简单地Dart类

定义Bicycle类

class Bicycle {
  int cadence;
  int speed;
  int gear;
}

void main() {
}
  • 如果在main()方法中需要访问命令行传过来的参数,可以使用main(List<String> args)方法。
  • 在Dart中可以在类之外编写代码、变量、方法、存取方法。
  • main()还是Bicycle类都默认是public的,Dart中没有public、private、protected等关键字。

定义一个Bicycle的构造函数

在Bicycle类中增加以下的构造函数:

Bicycle(this.cadence, this.speed, this.gear);
  • 在Dart中构造函数没有方法体是合法的。
  • 构造函数参数中使用this,可以直接对实例变量进行赋值,不用编写多与代码。
  • 上述代码与下列的代码功效相同。
Bicycle(int cadence, int speed, int gear) {
  this.cadence = cadence;
  this.speed = speed;
  this.gear = gear;
}

优化输出信息

所有的Dart类中都有一个toString()方法,可以直接复写这个方法来提供更具体的输出信息。

@override
String toString() => 'Bicycle: $speed mph';
  • 可以在字符串中使用${expression}方法来实现字符串模板的效果,如果该表达式仅是一个标识符,可以去掉花括号$variableName
  • 只有一行的方法可以使用=>来简写。

增加只读变量

可以在变量名前新增下划线_来标记它是私有的,就是说可以仅通过改变变量名来实现将变量标记为只读。

  int _speed = 0;

在Bicycle类中增加getter方法

int _speed = 0;
int get speed => _speed;
  • 未初始化的变量(即使是数字类型)的值都是null。
  • 默认情况下,Dart 会为所有公开的变量提供存取方法,除非你需要提供仅仅可读、可写,或者在某些情况下需要在 getter 方法中进行计算或是在 setter 方法中进行某些值得更新,否则都不需要再重新定义存取方法。
  • 在之前 Java 例子中,cadence 和 gear 都有自己的存取方法,而在此例子中,这些实例变量可以直接通过 bike.gear 或者 bike.cadence 访问到。

二、使用可选参数(而不是使用重载)

import 'dart:math';

class Rectangle {
  int width;
  int height;
  Point origin;
}

添加Rectangle构造方法

Rectangle({this.origin = const Point(0, 0), this.width = 0, this.height = 0});
  • this.origin, this.widththis.height 使用了 Dart 提供的简便方法来直接对类中的实例变量进行赋值。
  • this.origin, this.widththis.height 嵌套在闭合的花括号中 ({}) ,用来表示它们是可选的命名参数。
  • this.origin = const Point(0, 0) 这样的代码表明给实例变量 origin 提供了默认的值 Point(0,0),默认值必须是在编译期就可以确定的常量。上述代码中的构造方法为三个实例变量都提供了默认参数。

使用构造方法

main() {
  print(Rectangle(origin: const Point(10, 20), width: 100, height: 200));
  print(Rectangle(origin: const Point(10, 10)));
  print(Rectangle(width: 200));
  print(Rectangle());
}

三、创建工厂模式

在 Java 中工厂类是一个广泛使用的设计模式,它相比较直接对类进行实例化来说,具有诸多优势,比如隐藏实例化的具体细节,提供可以配置为其他类的能力,直接返回一个已有的对象而不是直接返回一个新的对象。

在该步骤中,将展示两种实现一个创建Shape的工厂类的方法。

  • 选项 1:创建一个顶层的方法
  • 选项2 :创建一个工厂模式的构造方法

在这个练习中,你将会使用一个 Shapes 实例来实例化形状的类,并输出打印出他们的面积:

import 'dart:math';

abstract class Shape {
  num get area;
}

class Circle implements Shape {
  final num radius;
  Circle(this.radius);
  num get area => pi * pow(radius, 2);
}

class Square implements Shape {
  final num side;
  Square(this.side);
  num get area => pow(side, 2);
}

main() {
  final circle = Circle(2);
  final square = Square(2);
  print(circle.area);
  print(square.area);
}

  • Dart支持抽象类。
  • 一个文本中可以定义多个类。

选项1:创建一个顶层的方法

Shape shapeFactory(String type) {
  if (type == 'circle') return Circle(2);
  if (type == 'square') return Square(2);
  throw 'Can\'t create $type.';
}

替换main()方法中前两行代码

final circle = shapeFactory('circle');
final square = shapeFactory('square');

选项2:创建一个工厂模式的构造方法

使用 Dart 的 factory 关键字来创建一个工厂模式的构造方法

// 在抽象类 Shape 中增加一个工厂模式的构造方法
abstract class Shape {
  factory Shape(String type) {
    if (type == 'circle') return Circle(2);
    if (type == 'square') return Square(2);
    throw 'Can\'t create $type.';
  }
  num get area;
}

替换main()方法中前两行

final circle = Shape('circle');
final square = Shape('square');

四、接口实现

Dart并没有提供 interface 关键字,但是每一个类都隐式地定义了一个接口

扩展Circle类,增加一个CircleMock:

class CircleMock implements Circle {}

// 上述代码会看到一个 Missing concrete implementations 的错误
// 添加两个实例变量 area 和 radius 即可修复这个问题

class CircleMock implements Circle {
  num area;
  num radius;
}
  • 虽然 CircleMock 并没有定义任何行为,但是在 Dart 中这是完全合法的,不会有任何报错。
License:  CC BY 4.0