Dart 类修饰符

类修饰符控制一个类或 mixin 如何被使用,无论是在其自身的库内部,还是在定义它的库的外部。

修饰符关键字位于类或 mixin 声明之前。例如,abstract class 定义了一个抽象类。可以出现在类声明之前的完整修饰符集合包括:

  • abstract
  • base
  • final
  • interface
  • sealed
  • mixin

只有 base 修饰符可以出现在 mixin 声明之前。修饰符不适用于其他声明,如 enumtypedef extension

在决定是否使用类修饰符时,考虑类的预期用途,以及类需要依赖的行为。

无修饰符

要允许任何库无限制地构造或子类型化,使用没有修饰符的类或 mixin 声明。默认情况下,你可以:

  • 构造类的新实例。
  • 扩展类以创建新的子类型。
  • 实现类或 mixin 的接口。
  • 混入 mixinmixin 类。

abstract

要定义一个不需要其全部接口的完全、具体实现的类,使用 abstract 修饰符。

  • 抽象类不能从任何库(无论是自己的还是外部的库)构造。抽象类通常有抽象方法。
  • 如果你希望你的抽象类看起来可以实例化,定义一个工厂构造函数。

base

要强制继承类或 mixin 的实现,使用 base 修饰符。基类禁止在其自身的库之外实现。这保证了:

  • 每当创建一个类的子类型的实例时,都会调用基类的构造函数。
  • 所有实现的私有成员都存在于子类型中。
  • 在基类中新增的成员不会破坏子类型,因为所有子类型都继承了新的成员。

你必须将实现或扩展基类的任何类标记为 basefinalsealed。这防止外部库破坏基类的保证。

interface

要定义一个接口,使用 interface 修饰符。定义接口的库外部的库可以实现接口,但不能扩展它。这保证了:

  • 当类的实例方法调用另一个实例方法时,它总是会调用来自同一个库的已知实现。

abstract interface

interface 修饰符最常用来定义纯接口。将 interfaceabstract 修饰符组合起来,定义一个抽象接口类。

  • 像接口类一样,其他库可以实现,但不能继承纯接口。像抽象类一样,纯接口可以有抽象成员。

final

要关闭类型层次结构,使用 final 修饰符。这防止从当前库外部的类进行子类型化。禁止继承和实现防止完全子类型化。这保证了:

  • 你可以安全地向API添加增量更改。
  • 你可以调用实例方法,知道它们在第三方子类中没有被覆盖。

final 类可以在同一库内被扩展或实现。final 修饰符包含 base 的效果,因此任何子类也必须标记为 basefinalsealed

sealed

要创建一个已知的、可枚举的子类型集合,使用 sealed 修饰符。这允许你创建一个在静态上确保是详尽无遗的那些子类型上的 switch

sealed 修饰符防止一个类在其自身的库之外被扩展或实现。sealed 类隐含地是抽象的。

  • 它们不能被自身构造。
  • 它们可以有工厂构造函数。
  • 它们可以为其子类定义构造函数。

然而,sealed 类的子类并不隐含地是抽象的。

编译器知道任何可能的直接子类型,因为它们只能在同一个库中存在。这允许编译器在 switch 没有详尽地处理所有可能的子类型时提醒你:

如果你不希望进行详尽的切换,或者希望能够在后续添加子类型而不破坏API,使用 final 修饰符。

组合修饰符

你可以组合一些修饰符进行分层限制。一个类声明可以按照以下顺序:

  1. (可选) abstract,描述类是否可以包含抽象成员并阻止实例化。
  2. (可选) baseinterfacefinalsealed中的一个,描述对其他库子类型化类的限制。
  3. (可选) mixin,描述声明是否可以被混入。
  4. 类关键字本身。

你不能组合一些修饰符,因为它们是矛盾的、冗余的,或者相互排斥的:

  • abstractsealed。一个 sealed 类总是隐含地是抽象的。
  • interfacefinalsealedmixin。这些访问修饰符阻止混入。