类修饰符

上一章节讨论了MixinMixin 类。 本章节将重点讨论类的修饰符及其组合

abstract

abstract class 用于声明抽象类,抽象类可包含抽象方法(即只有签名没有具体实现的方法),且不能被实例化。

// ex447.dart
abstract class Mammal {
  void breathe();
}

interface

使用 interface class 创建一个接口类(或简称接口),详见接口一节。

base

每个类(class)都隐式地定义了一个接口(interface),因而可以实现(implements)一个类(即实现类中的方法)。base 类为继承而生,在定义它的library之外,只能被继承,而不能被实现。

ex541.dart:

// ex541.dart
base class Vehicle { // 1
  void moveForward(int meters) {
    // ...
  }
}

base class Car implements Vehicle { // 2
  @override
  void moveForward(int meters) {
    // ...
  }
}

base class Motorcycle extends Vehicle { // 3
 
}

ex541a.dart:

// ex541a.dart
import 'ex541.dart';

base class Truck extends Vehicle { // 4
  int passengers = 4;

  @override
  void moveForward(int meters) {
    // ...
  }
}

// ERROR: 
// The class 'Vehicle' can't be implemented outside of its library 
// because it's a base class.
base class Train implements Vehicle { // 5
  @override
  void moveForward(int meters) {
    // ...
  }
}
  1. ex541.dart 文件中的Vehicle是一个 base 类,它有一个实例方法 moveForward(int);
  2. 同一文件中的 Car 实现了 Vehicle;
  3. 同一文件中的 Motorcycle 继承(extends)了 Vehicle;
  4. 另一文件( ex541a.dart )中的 Truck 继承了 Vehicle;
  5. 另一文件( ex541a.dart )中的 Train 试图实现 Vehicle,引发编译错误。

base 类有如下特点:

  • base类的子类/实现类必须使用basefinalsealed修饰,这是为了确保base的语义;
  • base类的子类自动继承了其可见的成员(字段/方法),因此为base类添加新的成员不会破坏子类,除非新成员与子类发生冲突;
  • 实例化base类的子类,必然导致base类的构造函数被调用。

sealed

sealed class用于创建密封类。密封类的子类是可穷举的,且必须与密封类位于同一个libary里。密封类是隐式抽象的,不能被实例化。

// ex344.dart
import 'dart:math' as math;

sealed class Shape {}

class Square implements Shape {
  final double length;
  Square(this.length);
}

class Circle implements Shape {
  final double radius;
  Circle(this.radius);
}

double calculateArea(Shape shape) => switch (shape) {
  Square(length: var l) => l * l,
  Circle(radius: var r) => math.pi * r * r,
};

密封类的一个特点是switch详尽性检查。假如还有一个类也实现或继承了 Shape,如:

class Rectangle extends Shape {}

calculateArea(Shape)函数会有编译错误:

 Error: The type 'Shape' is not exhaustively matched by the switch cases since it doesn't match 'Rectangle()'.
 - 'Shape' is from 'bin/ch03/ex344.dart'.
Try adding a wildcard pattern or cases that match 'Rectangle()'.
double calculateArea(Shape shape) => switch (shape) {
                                             ^

final

final类不能被外部libary继承或实现。final类的子类或实现类也必须是final类。

ex542.dart

// ex542.dart
final class Pet {}

final class Kitty extends Pet {}

final class Garfield implements Pet {}

ex542a.dart

// ex542a.dart
import 'ex542.dart';

// Error: The class 'Pet' can't be extended outside of its library
// because it's a final class
final class Doggy extends Pet {}

// Error: The class 'Pet' can't be implemented outside of its library
// because it's a final class.
final class Corgi implements Pet {}

由于final类只能被同一个library中的类继承或实现:

  • 你可以安全地对其进行修改;
  • 也不用担心其实例方法被其它的library重写。

修饰符的组合

下表列出了有效的修饰符的组合及其特性。

声明可实例化?可继承?可实现?Mixin?可穷举?
class✔️✔️✔️
base class✔️✔️
interface class✔️✔️
final class✔️
sealed class✔️
abstract class✔️✔️
abstract base class✔️
abstract interface class✔️
abstract final class
mixin class✔️✔️✔️✔️
base mixin class✔️✔️✔️
abstract mixin class✔️✔️✔️
abstract base mixin class✔️✔️
mixin✔️✔️
base mixin✔️

参考资料