关于 dart-api-design
面向 Dart 开发者的 API 设计指南,涵盖命名、类型签名、类修饰符、封装和参数选择。它还提供设计清单及使用 `dart analyze` 检查的工作流程。
主要功能
- 01命名与 API 规范
- 02Dart 3 类修饰符指南
- 03封装与相等性规则
- 04类型和参数设计
- 05API 清单与分析流程
适用场景
- 01设计新的 Dart 库 API
- 02审查类层次结构和公共成员
- 03运行 `dart analyze` 前检查签名
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ dart-lang/ skills --skill dart-api-design安装后在 Claude Code 中输入/dart-api-design确认已加载。
详细介绍
设计有效的 Dart API
目录
命名约定
采用一致且描述性强的命名,以便充分利用已有的领域知识和核心库知识。
- 属性与变量:
- 非布尔属性使用名词短语(例如,
pageCount、context.lineWidth)。 - 布尔属性使用非祈使动词短语(例如,
isEmpty、canClose)。优先使用“肯定”名称(例如,使用isConnected而不是isNotDisconnected)。
- 非布尔属性使用名词短语(例如,
- 方法与函数:
- 对副作用较大的操作使用祈使动词短语(例如,
list.add()、window.refresh())。 - 如果返回值是主要目的,则使用名词短语或非祈使动词短语(例如,
list.elementAt(3))。 - 避免以
get开头命名方法。使用 getter 或描述性动词(例如,downloadData())。 - 如果方法将状态复制到新对象中,则命名为
to___()(例如,list.toSet())。 - 如果方法返回由原始对象支持的不同表示形式,则命名为
as___()(例如,table.asMap())。
- 对副作用较大的操作使用祈使动词短语(例如,
- 类型参数:遵循标准助记符:
E(元素)、K/V(键/值)、R(返回类型)或T/S/U(单一类型)。
类修饰符与架构
使用 Dart 3 类修饰符进行可扩展设计并封装实现。应用修饰符来控制外部库的访问。
abstract:用于定义需要对其接口进行具体实现的类。无法实例化。base:用于强制继承类的实现。在类自身库之外禁止使用implements。保证调用基类构造函数。interface:用于定义纯接口。允许使用implements,但在该库之外禁止使用extends。可减少脆弱基类问题。final:用于封闭类型层级。在该库之外同时禁止使用extends和implements。保证 API 可安全地渐进式修改。sealed:用于创建已知且可枚举的子类型集合。支持针对子类型编写穷尽式switch语句。隐式为抽象类。
注意:可根据需要组合使用修饰符(例如,使用 abstract interface class 表示纯接口)。
成员与封装
- 封装:避免使用公共字段;使用 getter 和 setter 来封装并控制状态的访问与修改。
- Getter:对于概念上访问属性的操作,使用 getter。该操作不得接受参数、必须返回结果、不得产生用户可见的副作用,并且必须是幂等的。
- Setter:对于概念上更改属性的操作,使用 setter。该操作必须接受一个参数、改变状态,并且必须是幂等的。
- 不要定义没有对应 getter 的 setter。
- 不要为 setter 指定返回类型(它们本身返回
void)。
- 方法级联:避免仅为实现流畅接口而让方法返回
this。改用 Dart 的级联运算符(..)。 - 相等性:
- 如果重写了
==,就要重写hashCode。 - 避免为可变类定义自定义相等性。
- 不要让
==的参数可为 null(语言会自动处理null检查)。
- 如果重写了
类型与签名
- 类型别名:DO 使用类型别名(
typedef)简化复杂的函数签名。使用现代语法:typedef Comparison<T> = int Function(T a, T b);。 - 内联函数:对于简单的一次性回调,PREFER 使用内联函数类型,而不是 typedef(例如,
void Function(Event) callback)。 - 类型注解:
- DO 为未初始化的变量添加类型注解。
- DO 为非局部函数声明的返回值和参数添加类型注解。
- DON'T 为已初始化的局部变量或可推断的闭包参数冗余添加类型注解。
- 泛型:使用完整的泛型类型。AVOID 使用不完整的泛型类型(例如,使用
Completer<Map<String, int>>(),而不是Completer<Map>())。 - Dynamic 与 Object:AVOID 使用
dynamic,除非你明确希望禁用静态检查。使用Object?安全地接受任意值。 - 异步返回值:对于不产生值的异步成员,DO 使用
Future<void>作为返回类型。AVOID 将FutureOr<T>用作返回类型(它会迫使调用方检查类型)。
参数
- 命名参数:对于参数超过两个的函数,PREFER 使用命名参数,以提高调用处的可读性。
- 布尔参数:AVOID 使用位置布尔参数。改用命名参数。
- CONSIDER 在命名布尔参数中省略
is/can/has前缀(例如,使用Isolate.spawn(..., paused: true),而不是isPaused: true)。
- CONSIDER 在命名布尔参数中省略
- 可选位置参数:如果用户可能想省略前面的参数,AVOID 使用可选位置参数。改用命名参数。
- 范围:DO 使用包含在内的
start参数和不包含在内的end参数来接受范围(例如,substring(1, 3))。
工作流
任务进度:API 设计与实现
复制此清单,以便在设计新的 Dart 类或库 API 时跟踪进度。
- 定义类修饰符:
- 如果要定义不带实现的契约 ->
abstract interface class。 - 如果要提供必须由子类继承的实现 ->
base class。 - 如果要封闭类层次结构,禁止外部扩展或实现 ->
final class。 - 如果要定义可枚举的状态集合,以便进行穷尽式切换 ->
sealed class。
- 如果要定义不带实现的契约 ->
- 封装状态:
- 将内部字段设为私有(
_fieldName)。 - 通过 getter 暴露状态。
- 通过 setter 暴露修改操作(确保存在对应的 getter)。
- 将内部字段设为私有(
- 完善签名:
- 如果位置参数超过 2 个,将其转换为命名参数。
- 将位置布尔参数转换为命名布尔参数(去掉
is/can/has前缀)。 - 将复杂的函数参数提取为
typedef别名。
- 验证类型:
- 确保公共签名中不存在隐式的
dynamic类型。 - 将
FutureOr<T>返回类型替换为Future<T>。 - 确保异步 void 方法返回
Future<void>。
- 确保公共签名中不存在隐式的
- 运行验证器 -> 检查错误 -> 修复:
- 运行
dart analyze,检查缺失的注解、未处理的 sealed class switch 分支以及 linter 违规项。在最终确定 API 之前修复所有警告。
- 运行
评论
支持 Markdown