mcpField
D
design-patterns

design-patterns

github.com/robsonrung开发266 次安装2 天前更新
代码仓库

关于 design-patterns

为代码结构问题提供设计模式识别视角的 Agent 技能,帮助开发者判断何时采用模式、何时保持简单。它先检查设计原则与实际变更压力,并明确说明模式带来的成本。

主要功能

  1. 01按问题症状匹配候选模式
  2. 02先检查设计原则与简单方案
  3. 03涵盖常见设计模式及适用情形
  4. 04建议说明结构决策的成本

适用场景

  1. 01评估是否需要 Strategy 或 Decorator
  2. 02梳理重复创建对象的处理方式
  3. 03为结构建议说明取舍与复杂度

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/robsonrung/rar-skills --skill design-patterns

安装后在 Claude Code 中输入/design-patterns确认已加载。

附带文件references/patterns.md

详细介绍

设计模式

从《Head First Design Patterns》(Freeman 和 Robson,第 2 版)中提炼出的模式识别视角。目标不是应用模式,而是看清模式何时自然适用、何时不适用,然后选择能解决实际问题的最简单方案。

首先要守住底线

这本书最重要的教训出现在最后一章,而不是第一章:大多数代码都不该使用有名有姓的模式。

  • 保持简单(KISS)。 设计时,要用尽可能简单的方式解决问题。目标是简单,而不是“我该怎么在这里应用一种模式?”普通函数、map 或提前返回往往就是正确答案,其他开发者也会赞赏这种简洁。
  • 模式并非没有代价。 每种模式都会增加类、间接层和层次——需要阅读和追踪的内容更多,有时效率也更低。只有当它带来的灵活性确实是设计_实际需要的_时,这种代价才值得付出。
  • 在需求已经出现时引入模式,而不是提前预想。 如果更简单的方案可能行得通,就先给它机会。只有确定模式能解决眼下遇到的实际问题时,才考虑采用——例如某处反复变化,或某个扩展点总是难以处理,而不是为了应对假设中的未来需求。
  • 退回到设计原则(见下文)通常就能化解问题,而不必使用任何有名有姓的模式。如果确实如此,就别勉强使用模式。

因此,对于“这里该用哪种模式?”这个问题,坦诚的回答有时是**“一种也不用——这里有更简单的结构。”** 下文的“输出形式”一节体现了这一点,也明确规定每条建议都要说明其代价。

如何运用这一视角

当问题涉及代码结构时,按以下顺序进行:

  1. 说清压力所在。 实际上什么地方难处理?通常是以下几种情况之一:行为多变且不断变化、相似类之间存在重复、结构僵化而难以扩展、耦合紧密,或对象创建分散且带有条件判断。
  2. 检查设计原则。 模式正是建立在这些基础之上的。很多时候,直接应用某条原则就能彻底解决问题,无需使用有名有姓的模式。
  3. 然后才根据症状表匹配模式。 如果两种模式都适用,优先选择机制更少的那种。
  4. 使用共同的词汇。 一旦某种模式确实适用,就_说出它的名称_——“这是 Strategy”,“那是 Decorator”。共同的名称能用一个词向下一位开发者传达整个设计(意图、结构和权衡)。这种沟通价值是了解模式值得付出的原因之一。

设计原则(先检查这些)

这些原则比任何单独的模式都更普遍有用。大多数优秀的重构,不过是直接应用了其中一条原则。

  1. 封装变化。 找出会变化的部分,并将它们与保持不变的部分分离,让变化集中在一处。
  2. 面向接口编程,而非面向实现编程。 依赖某种能力(类型/抽象),而不是具体类,这样就能替换实现。
  3. 优先使用组合,而非继承。 “HAS-A 往往优于 IS-A。”组合行为比将行为锁定在类层次结构中更灵活。
  4. 努力让交互对象之间保持松耦合——它们应该尽可能少地了解彼此。
  5. 开闭原则: 类应该对扩展开放、对修改关闭——无需修改经过测试的代码,就能添加新行为。
  6. 依赖倒置: 依赖抽象,而不是具体类——高层代码不应受制于底层细节。
  7. 最少知识原则(迪米特法则): 只与直接的朋友交谈——避免 a.getB().getC().doThing() 这样的长链。
  8. 好莱坞原则: “别找我们,我们会找你”——让高层组件控制何时调用低层组件(控制反转),而不是反过来。
  9. 单一职责: 一个类应该只有一个引起它变化的原因。每个类只承担一项职责。

症状 → 模式对照表

将你指出的_压力_与候选项匹配。这只是起点,不是定论——在做决定前,请阅读 references/patterns.md 中对应模式的条目(其中包含“何时属于过度设计”)。

痛点候选模式
大量 if/else/switch 用于在可互换的行为之间进行选择策略(由调用方/配置选择行为)或 状态(行为由对象自身的状态驱动,并带有状态转换)
行为必须在运行时改变,或存在许多可选行为的组合策略;对于可堆叠的附加功能,使用 装饰器
一个对象的变化必须通知许多其他对象;你正在手动编写回调连接观察者
希望在不造成子类爆炸的情况下,向对象包装/叠加职责装饰器
代码中到处散布着 new ConcreteThing();创建逻辑有条件分支且重复工厂方法(单个产品)、抽象工厂(相关产品族),或直接使用创建函数
只需一个共享实例/单一协调点单例(但模块级值或 DI 通常更简单,也更易测试)
希望对_操作_进行参数化、排队、记录日志或撤销命令
两种不兼容的接口需要协同工作适配器
复杂子系统需要一个简单的入口外观
多个方法共享相同的骨架,但有几个步骤不同模板方法(继承)或将变化步骤传入(策略式)
遍历集合时不暴露其内部结构迭代器(大多数语言都内置了这种能力)
存在整体与部分构成的树形结构,客户端应以统一方式处理叶节点和分支组合
控制对对象的访问——延迟加载、远程访问、权限检查、缓存代理
抽象和实现各自独立变化,组合数量不断增加桥接
需要逐步构建复杂对象/存在许多可选字段构建器
请求应沿链传递,直到被某个处理者处理责任链
在不修改固定对象结构中各个类的情况下添加新操作访问者
捕获并恢复对象状态(撤销/快照)备忘录
许多对象彼此多对多通信;协调逻辑错综复杂中介者
大量相似的细粒度对象消耗大量内存享元
通过复制已配置的实例来创建新对象原型
解释小型语言/语法中的语句解释器
交互式应用中,数据、呈现和输入处理相互纠缠复合/MVC(观察者 + 策略 + 组合)

完整目录包含每种模式的一句话定义、表明适用的代码异味、结构示意、相关模式,以及何时属于过度设计。请阅读 references/patterns.md。只阅读与当前情况相关的条目;内容按模式组织,方便你直接跳转到对应模式。

在 design-gate 中,使用调用方的规范 gate 结果。这将取代独立的输出和编辑机制。将特定视角的结论放在 findings 或 review_focus 中,并使用稳定的 finding ID。在访谈中,将决策字段补充到现有的决策记录中。

输出形式

就结构提供建议时,优先采用以下形式,让建议切实可行、不夸大其词:

  • 实际压力: 用一句话说明这里真正难以更改的是什么。
  • 最简单的方案: 说明最朴素的可行方案(通常是不使用模式)。明确指出它是否足够。
  • 模式(如有必要): 使用共享词汇说出模式名称,并简要说明它如何映射到这段代码。
  • 代价: 说明它会增加哪些间接层/类,以及为什么在_此处_值得付出这些代价。如果说不出代价,就再仔细看看。

建议“无需模式,这里是三行实现”是成功,而不是敷衍。

评论

支持 Markdown