Dart 是一门使用类单继承的语言, 所有对象都是类的实例, 且所有类都是 Object 类的子类。

定义类

类的定义使用 class 关键字。

class Point {
  num x;
  num y;
  num z;
}

实例化

我们可以通过 new 关键字和构造函数进行类的实例化操作。一个类如果没有显式定义构造函数, 将会有默认的空构造函数。

var point = new Point();
print(point.hasCode);

构造函数

如果只是进行简单的参数传递赋值, 有两种简单的方式:

class Point {
  num x;
  num y;
  num z;

  // 第一个值传递给 this.x,第二个值传递给 this.y
  Point(this.x, this.y, z) {
    this.z = z;
  }
class Point {
  num x;
  num y;
  num z;

  // 命名构造函数, 格式为 Class.name(var param)
  Point.fromeList(var list):
    x = list[0], y = list[1], z = list[2] { // 使用冒号初始化变量
  }

  // 这个构造函数可以简写为
  // Point.fromeList(var list): this(list[0], list[1], list[2]);
}

常量构造函数

如果需要创建不可变的对象, 那么构造函数前需要添加 const 关键字:

class ImmutablePoint {
  final num x;
  final num y;

  // 常量构造函数
  const ImmutablePoint(this.x, this.y);

  // 创建一个常量对象不能用 new,要用 const
  static final ImmutablePoint origin = const ImmutablePoint(0, 0);
}

工厂构造函数

当前面提到的构造函数无法满足需求时, 你还可以选择工厂构造函数, 需要添加 factory 关键字:

class Logger {
    final String name;
    bool mute = false;

    // 变量前加下划线表示私有属性
    static final Map<String, Logger> _cache = <String, Logger>{};

    factory Logger(String name) {
        if (_cache.containsKey(name)) {
            return _cache[name];
        } else {
            final logger = new Logger._internal(name);
            _cache[name] = logger;
            return logger;
        }
    }

    Logger._internal(this.name);

    void log(String msg) {
        if (!mute) {
            print(msg);
        }
    }
}

var logger = new Logger('UI');
logger.log('Button clicked');

继承

你可以通过 extends 关键字指明父类, 未指明父类时, 默认继承自 Object 类。

class Rectangle {
  num x;
  num y;
  num width;
  num height;

  Rectangle(num this.height, num this.width);
}

// Square 继承 Rectangle
class Square extends Rectangle {
  // 调用超类的构造函数
  Square(num size): super(size, size);
}

toString()

你可以选择为一个类实现 String toString() 函数:

class Point {
  num x;
  num y;

  Point(this.x, this.y) {}
  String toString() => 'Point(x: $x, y: $y)';
}

void main() {
  var p = new Point(1, 2);
  print(p); // 默认调用 toString() 函数
}

Getter & Setter

每一个字段都对应一对隐式的 Getter/Setter。对于常量, 则只有 Getter 方法。

你可以使用 get/set 进行扩展:

class Rectangle {
  num x;
  num y;
  num width;
  num height;

  Rectangle(this.x, this.y, this.width, this.height);

  // right 和 bottom 两个属性的计算方法:

  num get right => x + width;
  set right(num value) => x = value - width;

  num get bottom => y + height;
  set bottom(num value) => y = value - height;
}

main() {
  var rect = new Rectangle(3, 4, 20, 15);
  assert(rect.x == 3);
  rect.right = 12;
  assert(rect.x == -8);
}

抽象类/接口

通过 abstract 我们可以定义一个抽象类/接口。抽象类不可以无法实例化, 通过 implements 指明并实现。抽象方法不需要关键字声明, 直接使用 ; 结束即可。

// 定义 Shape 抽象类/接口
abstract class Shape {

  // 抽象方法, 是隐式接口的一部分
  num perimeter();
}

// 为 Rectangle 实现 Shape 接口
class Rectangle implements Shape {
  final num height, width;

  Rectangle(num this.height, num this.width);

  // 实现了 Shape 接口要求的 perimeter 方法
  num perimeter() => 2 * height + 2 * width;
}

// Square 继承 Rectangle
class Square extends Rectangle {
  // 调用超类的构造函数
  Square(num size): super(size, size);
}