Class modifiers
版本说明
除了abstract
之外,类修饰符需要 Dart 语言版本至少为 3.0。
类修饰符控制了类或 mixin 的使用方式,无论是在其自己的库内部,还是在其定义所在的库外部。
修饰符关键字位于类或 mixin 声明之前。例如,abstract class
定义了一个抽象类。可以出现在类声明之前的完整修饰符集合包括:
abstract
base
final
interface
sealed
mixin
只有 base
修饰符可以出现在 mixin
声明之前。这些修饰符不适用于其他声明,如 enum
、typedef
、extension
或 extension type
。
在决定是否使用类修饰符时,请考虑类的预期用途以及该类需要依赖哪些行为。
提示
如果你已经熟悉 Dart 的类修饰符,只想查看它们的组合行为大纲或复习一下,请查阅类修饰符参考。如果你维护一个库,请阅读面向 API 维护者的类修饰符页面,以获取有关如何为你的库应对这些更改的指导。
无修饰符
要允许在任何库中无限制地进行构造或子类型化,请使用不带修饰符的类或 mixin 声明。默认情况下,你可以:
- 构造类的新实例。
- 继承一个类以创建新的子类型。
- 实现一个类或 mixin 的接口。
- 混入一个 mixin 或 mixin class。
abstract
要定义一个不需要为其整个接口提供完整、具体实现的类,请使用 abstract
修饰符。
抽象类不能在任何库中被构造,无论是其自己的库还是外部库。抽象类通常有抽象方法。
a.dart
1 | abstract class Vehicle { |
b.dart
1 | import 'a.dart'; |
如果你希望你的抽象类看起来是可实例化的,请定义一个工厂构造函数。
base
要强制继承一个类或 mixin 的实现,请使用 base
修饰符。base
类禁止在其自己的库之外被实现。这保证了:
- 每当创建该类的子类型的实例时,都会调用基类构造函数。
- 所有已实现的私有成员都存在于子类型中。
- 在基类中新增一个已实现的成员不会破坏子类型,因为所有子类型都会继承这个新成员。
- 除非子类型已经声明了一个同名且签名不兼容的成员。
你必须将任何实现或继承 base
类的类标记为 base
、final
或 sealed
。这可以防止外部库破坏 base
类的保证。
a.dart
1 | base class Vehicle { |
b.dart
1 | import 'a.dart'; |
interface
要定义一个接口,请使用 interface
修饰符。接口定义库之外的库可以实现该接口,但不能继承它。这保证了:
- 当类的实例方法调用
this
上的另一个实例方法时,它将始终调用来自同一个库的已知方法实现。 - 其他库不能覆写
interface
类自己的方法后续可能以意想不到的方式调用的方法。这减少了脆弱基类问题。
a.dart
1 | interface class Vehicle { |
b.dart
1 | import 'a.dart'; |
abstract interface
interface
修饰符最常见的用途是定义一个纯接口。将 interface
和 abstract
修饰符组合起来,可以得到一个**抽象接口类 (abstract interface class)**。
像 interface
类一样,其他库可以实现但不能继承一个纯接口。像 abstract
类一样,一个纯接口可以有抽象成员。
final
要关闭类型层次结构,请使用 final
修饰符。这会阻止在当前库之外对类进行子类型化。同时禁止继承和实现,从而完全阻止了子类型化。这保证了:
- 你可以安全地对 API 进行增量更改。
- 你可以调用实例方法,并确信它们没有在第三方子类中被覆写。
final
类可以在同一个库中被继承或实现。final
修饰符包含了 base
的效果,因此任何子类也必须被标记为 base
、final
或 sealed
。
a.dart
1 | final class Vehicle { |
b.dart
1 | import 'a.dart'; |
sealed
要创建一个已知的、可枚举的子类型集合,请使用 sealed
修饰符。这允许你创建一个针对这些子类型的 switch
语句,并静态地确保其是**穷尽的 (exhaustive)**。
sealed
修饰符阻止一个类在其自己的库之外被继承或实现。密封类是隐式抽象的。
- 它们本身不能被构造。
- 它们可以有工厂构造函数。
- 它们可以为它们的子类定义构造函数。
然而,密封类的子类并不是隐式抽象的。
编译器知道所有可能的直接子类型,因为它们只能存在于同一个库中。这使得编译器能够在 switch
语句的 case
没有穷尽地处理所有可能的子类型时提醒你:
1 | sealed class Vehicle {} |
如果你不希望进行穷尽的 switch
检查,或者希望以后能够在不破坏 API 的情况下添加子类型,请使用 final
修饰符。更深入的比较,请阅读 sealed
与 final
的对比。
组合修饰符
你可以组合一些修饰符以实现分层的限制。一个类声明可以按顺序包含:
- (可选)
abstract
,描述该类是否可以包含抽象成员并阻止实例化。 - (可选)
base
、interface
、final
或sealed
之一,描述对其他库子类型化该类的限制。 - (可选)
mixin
,描述该声明是否可以被混入。 class
关键字本身。
你不能组合某些修饰符,因为它们是矛盾的、冗余的或互斥的:
abstract
和sealed
。一个sealed
类是隐式抽象的。interface
、final
或sealed
和mixin
。这些访问修饰符会阻止混入。
有关类修饰符如何组合的进一步指导,请查阅类修饰符参考。