关于 gof-prototype
gof-prototype 是讲解原型设计模式的技能,面向需要从已有实例创建变体的开发者。内容涵盖 Kotlin 的 data class.copy()、原型注册表及浅拷贝风险。
主要功能
- 01说明简单原型与原型注册表
- 02介绍 Kotlin data class.copy()
- 03提供使用与避免场景判断
- 04指出浅拷贝和共享状态风险
- 05列举常见反模式与相关模式
适用场景
- 01从模板实例创建字段略有不同的对象
- 02维护可按名称获取并定制的原型
- 03评估对象是否适合采用复制创建
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ yonatankarp/ software-design-skills --skill gof-prototype安装后在 Claude Code 中输入/gof-prototype确认已加载。
详细介绍
单行摘要
通过复制现有实例(原型)而不是调用构造函数来创建新对象——当构造开销较大、只想更改少数几个字段,或拥有预设形状的注册表时,这种方式很有用。
何时使用此技能
- 对象构造开销较大,或带有不希望重复触发的副作用。
- 你有一个“模板”实例,并希望通过更改少数字段来生成它的变体。
- 你需要一个预设实例的注册表,供使用者克隆并自定义。
- Kotlin 中的典型实现:
data class.copy(field = newValue)正是这种模式。
何时不使用此技能
- 构造简单且无状态——直接调用构造函数即可。
- “复制”必须是复杂对象图的深拷贝——原型模式的约定通常是浅拷贝;深拷贝是另一个问题。
- 你试图通过“复制”尚不存在的东西来绕过棘手的构造问题——这不是好迹象。
核心内容
有两种形式:
简单原型。 对象有一个 clone()(或 copy())方法,用相同的字段值返回一个新实例。调用方获取一个基础实例,复制它,然后修改副本。在 Kotlin 中,每个 data class 都自带 copy(),还可以选择通过命名参数覆盖字段。
val baseRequest = HttpRequest(method = GET, url = "/users", headers = standardHeaders)
val authedRequest = baseRequest.copy(headers = standardHeaders + auth)
原型注册表。 一个中央注册表保存以名称命名的原型实例。使用者按名称("weekday-shift"、"weekend-shift")向注册表请求原型,并获得一个可自定义的克隆副本。当原型是配置数据而非代码时,这种方式很有用。
这种模式的价值在于让意图一目了然:“这个新实例与那个已有实例相似,但有这些差异”,比重新构造每个字段更清晰。
决策启发
- 在 Kotlin 中,
data class.copy()是默认的原型模式实现。只有当原型有名称、经过配置或数量众多时,才使用显式注册表。 - 对于非
data class类型,应审慎决定copy()要执行深拷贝还是浅拷贝,并将其记录在文档中。 - 注意嵌套的可变状态——
data class的copy()复制的是引用,而不是被引用的对象。修改共享的嵌套列表会同时影响原件和副本。
反模式
clone()方法只做到几乎是副本,而非完全相同——可能会意外生成细微不同的实例。要么精确复制,要么重命名该方法。- 多个使用者共享可变原型,却不进行复制——注册表中的实例会逐渐发生变化。
- 把原型模式当作缺少构造函数的权宜之计——应该修复构造函数。
另请参阅
gof-factory— 有时比原型模式更合适,尤其是每个“变体”实际上都是不同的具体类型时。gof-builder— 当变体体现在结构上(步骤不同),而非字段覆盖时使用。gof-kotlin-idioms—data class.copy()是语言特性实现的原型模式。
参考资料
- Design Patterns(GoF,1994),第 3 章 — Prototype。(未收录于 HFDP 第 2 版。)
- Kotlin Design Patterns and Best Practices(Alexey Soshin),第 2 章 — Prototype,以 Kotlin 的
copy()为核心展开。
评论
支持 Markdown