从 面向对象设计原则(SOLID) 来看,Dart 中的 sealed class 是一个非常契合多项设计原则的工具。我们可以逐条分析它与 SOLID 原则的关系:
🔹 S - 单一职责原则(SRP)
每个类应该只有一个职责,且该职责应该完全封装在类中。
sealed class 强制你将一个有限状态系统拆分为多个子类,每个子类负责自己的逻辑(如状态、错误、响应等),符合 SRP:
sealed class NetworkResult {}
class Success extends NetworkResult {
final String data;
Success(this.data);
}
class Failure extends NetworkResult {
final String message;
Failure(this.message);
}
✅ Success 只负责成功的结构,Failure 只负责失败的结构,职责单一,清晰分离。
🔹 O - 开闭原则(OCP)
对扩展开放,对修改封闭。
sealed class 可以通过新增子类来扩展系统,而不必修改已有逻辑。
// 想支持超时状态,只需要新增 Timeout:
class Timeout extends NetworkResult {}
✅ 不修改 Success / Failure 等已有子类,系统即可扩展,符合开闭原则。
🔹 L - 里氏替换原则(LSP)
子类对象必须能够替换父类对象使用。
sealed class 定义的是一种类型家族,你可以放心地将任一子类替换为父类使用。
void handle(NetworkResult result) {
// 所有子类都可替换 NetworkResult 类型处理
}
✅ 所有子类(如 Success, Failure)都可以无缝用于 NetworkResult,满足 LSP。
🔹 I - 接口隔离原则(ISP)
不要强迫客户端依赖它们不使用的方法。
虽然 Dart 没有接口关键字,但 sealed class 的子类可以拥有各自方法和字段,不共享不必要的结构。
class Success extends NetworkResult {
final String data;
void logSuccess() {}
}
class Failure extends NetworkResult {
final String error;
void reportError() {}
}
✅ 不会让子类被强制实现无关的方法,各子类职责清晰,接口最小化。
🔹 D - 依赖倒置原则(DIP)
高层模块不应该依赖低层模块,二者都应该依赖抽象。
在实际架构中,使用 sealed class 作为抽象模型,高层业务代码依赖的是 sealed 的抽象,而不是具体实现:
void process(NetworkResult result) {
switch (result) {
case Success(:var data):
print('Got $data');
break;
case Failure(:var message):
print('Error: $message');
break;
}
}
✅ 业务逻辑依赖抽象类型 NetworkResult,而不是具体子类,符合依赖倒置。
✅ 总结
| 设计原则 | sealed class 是否契合 | 理由 |
|---|---|---|
| SRP | ✅ | 每个子类职责单一 |
| OCP | ✅ | 新增子类即可扩展 |
| LSP | ✅ | 子类可以无缝替代父类使用 |
| ISP | ✅ | 子类仅实现自身需要的结构 |
| DIP | ✅ | 高层依赖抽象 sealed class 类型 |