dart-api-design
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDart Effective Design
Dart 有效设计
Goal
目标
Analyzes and refactors Dart code to enforce idiomatic API design, strict type safety, and robust object-oriented hierarchies. Applies Dart 3 class modifiers to control extension and implementation boundaries, ensures proper encapsulation through getters and setters, and standardizes naming conventions for predictable, maintainable libraries.
分析并重构Dart代码,以遵循惯用的API设计、严格的类型安全和健壮的面向对象层级结构。应用Dart 3的类修饰符来控制扩展和实现边界,通过getter和setter确保适当的封装,并标准化命名约定,以打造可预测、可维护的库。
Instructions
操作指南
-
Apply Naming Conventions
- Use noun phrases for non-boolean properties/variables (e.g., ).
list.length - Use non-imperative verb phrases for boolean properties (e.g., ,
isEmpty).canClose - Use imperative verbs for methods with side effects (e.g., ).
list.add() - Use for methods that copy state to a new object (e.g.,
to___()).list.toSet() - Use for methods returning a different representation backed by the original object (e.g.,
as___()).map.asMap() - Follow standard generic type parameter mnemonics: (elements),
E/K(key/value),V(return type),R/T/S(general).U
- Use noun phrases for non-boolean properties/variables (e.g.,
-
Determine Class Modifiers (Decision Logic) Evaluate every class declaration against the intended API boundary.
- Does the class require a full, concrete implementation of its interface?
- No: Use .
abstract class
- No: Use
- Should external libraries be allowed to implement the class interface, but NOT inherit its implementation?
- Yes: Use (or
interface classfor pure interfaces).abstract interface class
- Yes: Use
- Should external libraries be allowed to inherit the implementation, but NOT implement the interface?
- Yes: Use . (Note: Subclasses must be marked
base class,base, orfinal).sealed
- Yes: Use
- Is the class part of a closed, enumerable set of subtypes for exhaustive switching?
- Yes: Use .
sealed class
- Yes: Use
- Should the class be completely locked from external extension and implementation?
- Yes: Use .
final class
- Yes: Use
- Does the class contain only a single abstract method (e.g., )?
call- Yes: Convert to a function type.
typedef
- Yes: Convert to a
- Does the class contain only static members?
- Yes: Move members to top-level library declarations.
- STOP AND ASK THE USER: If the extension/implementation intent of a public class is ambiguous, pause and ask the user to clarify the intended API boundary before applying modifiers.
- Does the class require a full, concrete implementation of its interface?
-
Enforce Parameter Rules
- Prefer named parameters for functions with more than two arguments.
- Avoid positional boolean parameters.
- Omit the verb (,
is,can) for named boolean parameters.has - Use inclusive start and exclusive end parameters for ranges.
dart// GOOD void configure(String name, {bool paused = false, bool growable = true}) {} var sub = items.sublist(0, 3); // BAD void configure(String name, bool isPaused, bool canGrow) {} -
Manage State and Encapsulation
- Prefer for fields and top-level variables.
final - Avoid public fields; use getters and setters for encapsulation.
- Do not define a setter without a corresponding getter.
- Avoid public fields without initializers (this implicitly exposes a setter).
late final - Use getters for operations that conceptually access properties (no arguments, returns a result, idempotent, no user-visible side effects).
dart// GOOD class Rectangle { double _width; Rectangle(this._width); double get width => _width; set width(double value) => _width = value; double get area => _width * _width; // Idempotent, no side effects } - Prefer
-
Apply Strict Type Annotations
- Annotate variables without initializers.
- Annotate fields and top-level variables if the type isn't obvious.
- Annotate return types and parameter types on non-local function declarations.
- Do NOT redundantly annotate initialized local variables.
- Do NOT annotate inferred parameter types on function expressions (closures).
- Do NOT type annotate initializing formals ().
this.x - Use inline function types over legacy typedefs.
- Use (not
Future<void>orvoid) for async members that do not produce values.Future<Null> - Avoid as a return type; return
FutureOr<T>instead.Future<T>
dart// GOOD typedef Comparison<T> = int Function(T a, T b); class FilteredObservable { final bool Function(Event) _predicate; // Inline function type FilteredObservable(this._predicate); } -
Implement Equality Safely
- If overriding , you MUST override
==.hashCode - Ensure is reflexive, symmetric, and transitive.
== - Avoid defining custom equality for mutable classes.
- Do not make the parameter to nullable (
==instead ofObject).Object?
dart// GOOD class Person { final String name; Person(this.name); bool operator ==(Object other) => other is Person && name == other.name; int get hashCode => name.hashCode; } - If overriding
-
应用命名约定
- 非布尔类型的属性/变量使用名词短语(例如:)。
list.length - 布尔类型的属性使用非命令式动词短语(例如:、
isEmpty)。canClose - 有副作用的方法使用命令式动词(例如:)。
list.add() - 用于将状态复制到新对象的方法使用格式(例如:
to___())。list.toSet() - 用于返回由原对象支持的不同表示形式的方法使用格式(例如:
as___())。map.asMap() - 遵循标准泛型类型参数助记符:(元素)、
E/K(键/值)、V(返回类型)、R/T/S(通用类型)。U
- 非布尔类型的属性/变量使用名词短语(例如:
-
确定类修饰符(决策逻辑) 根据预期的API边界评估每个类声明。
- 该类是否需要其接口的完整具体实现?
- 否: 使用。
abstract class
- 否: 使用
- 是否允许外部库实现该类接口,但不继承其实现?
- 是: 使用(纯接口使用
interface class)。abstract interface class
- 是: 使用
- 是否允许外部库继承其实现,但不实现该接口?
- 是: 使用。(注意:子类必须标记为
base class、base或final)。sealed
- 是: 使用
- 该类是否属于可穷举切换的封闭可枚举子类型集合?
- 是: 使用。
sealed class
- 是: 使用
- 是否要完全禁止外部扩展和实现该类?
- 是: 使用。
final class
- 是: 使用
- 该类是否仅包含单个抽象方法(例如)?
call- 是: 转换为函数类型。
typedef
- 是: 转换为
- 该类是否仅包含静态成员?
- 是: 将成员移至顶级库声明中。
- 暂停并询问用户: 如果公共类的扩展/实现意图不明确,请暂停并询问用户以明确预期的API边界,再应用修饰符。
- 该类是否需要其接口的完整具体实现?
-
实施参数规则
- 参数超过两个的函数优先使用命名参数。
- 避免使用位置布尔参数。
- 命名布尔参数省略动词(、
is、can)。has - 范围参数使用包含起始值和排除结束值的方式。
dart// GOOD void configure(String name, {bool paused = false, bool growable = true}) {} var sub = items.sublist(0, 3); // BAD void configure(String name, bool isPaused, bool canGrow) {} -
管理状态与封装
- 字段和顶级变量优先使用。
final - 避免使用公共字段;使用getter和setter实现封装。
- 不要定义没有对应getter的setter。
- 避免使用未初始化的公共字段(这会隐式暴露setter)。
late final - 概念上属于访问属性的操作使用getter(无参数、返回结果、幂等、无用户可见副作用)。
dart// GOOD class Rectangle { double _width; Rectangle(this._width); double get width => _width; set width(double value) => _width = value; double get area => _width * _width; // 幂等,无副作用 } - 字段和顶级变量优先使用
-
应用严格类型注解
- 未初始化的变量添加类型注解。
- 类型不明确的字段和顶级变量添加类型注解。
- 非局部函数声明添加返回类型和参数类型注解。
- 已初始化的局部变量不要重复添加类型注解。
- 函数表达式(闭包)的推断参数类型不要添加注解。
- 初始化形式参数()不要添加类型注解。
this.x - 使用内联函数类型替代旧版typedef。
- 不产生值的异步成员使用(而非
Future<void>或void)。Future<Null> - 避免使用作为返回类型;应返回
FutureOr<T>。Future<T>
dart// GOOD typedef Comparison<T> = int Function(T a, T b); class FilteredObservable { final bool Function(Event) _predicate; // 内联函数类型 FilteredObservable(this._predicate); } -
安全实现相等性
- 如果重写,必须同时重写
==。hashCode - 确保满足自反性、对称性和传递性。
== - 避免为可变类定义自定义相等性。
- 的参数不要设为可空类型(使用
==而非Object)。Object?
dart// GOOD class Person { final String name; Person(this.name); bool operator ==(Object other) => other is Person && name == other.name; int get hashCode => name.hashCode; } - 如果重写
Constraints
约束条件
- No Positional Booleans: Never generate function signatures with positional boolean arguments.
- No Legacy Typedefs: Never use the syntax. Always use
typedef name(args).typedef Name = ReturnType Function(args) - No Faked Overloading: Do not use runtime type tests () to fake method overloading. Create distinctly named methods instead.
is - No Nullable Collections: Avoid returning nullable ,
Future, or collection types. Return empty collections instead.Stream - No Fluent : Avoid returning
thisfrom methods just to enable a fluent interface; rely on Dart's cascade operator (this) instead... - No Raw Types: Never write incomplete generic types (e.g., ). Always specify type arguments or rely on complete inference.
List numbers = [] - Related Skills: ,
dart-effective-style.dart-package-management
- 禁止位置布尔参数: 永远不要生成包含位置布尔参数的函数签名。
- 禁止旧版Typedef: 永远不要使用语法。始终使用
typedef name(args)。typedef Name = ReturnType Function(args) - 禁止模拟重载: 不要使用运行时类型测试()来模拟方法重载。应创建名称明确的方法。
is - 禁止可空集合: 避免返回可空的、
Future或集合类型。应返回空集合。Stream - 禁止Fluent : 不要为了实现流畅接口而从方法返回
this;应依赖Dart的级联运算符(this)。.. - 禁止原始类型: 永远不要编写不完整的泛型类型(例如:)。始终指定类型参数或依赖完整的类型推断。
List numbers = [] - 相关技能: 、
dart-effective-style。dart-package-management