关于 codeprobe-patterns
这是 codeprobe 的子技能,用于发现有具体问题支撑的设计模式机会,并识别徒增复杂度的模式。适用于能够用明确模式解决实际设计问题的代码审查,不会无缘由地建议使用模式。
主要功能
- 01识别有依据的模式机会
- 02检测误用的设计模式
- 03避免与其他 codeprobe 技能重复
- 04结合复杂度和代码上下文判断
适用场景
- 01评估复杂对象的构建方式
- 02审查重复的条件式对象创建
- 03查找方法中重复的横切逻辑
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ machineroom-dev/ codeprobe --skill codeprobe-patterns安装后在 Claude Code 中输入/codeprobe-patterns确认已加载。
详细介绍
独立模式
如果直接调用(而非通过编排器调用),必须先:
- 阅读
../codeprobe/shared-preamble.md(相对于此 SKILL.md 的位置解析,即同级的codeprobe技能目录,而非用户的项目),了解输出约定、执行模式和限制。 - 根据项目的技术栈,从
../codeprobe/references/(按相同方式解析)加载适用的参考文件。 - 除非用户另有指定,否则默认使用
full模式。
设计模式顾问
领域范围
切勿为了使用模式而推荐模式。只有当代码中存在某个模式可以解决的具体问题时,才指出使用该模式的机会。如果代码在不使用模式的情况下也能正常工作、易于阅读且易于维护,就不要提出建议。
此子技能可检测两类设计模式问题:
- 模式应用机会 — 在代码中,特定的 GoF 模式或架构模式能够解决可观察问题(复杂性、重复、僵化、隐藏依赖)的地方。
- 反模式 — 错误使用的模式会增加复杂性、间接层或抽象层,却无法带来可衡量的收益。
不应标记的内容
-
针对类型/状态的
switch语句已由codeprobe-solid(OCP-xxx)标记。 只有在能够推荐一种具体的命名模式(例如 Strategy、State),且能说明它相较于当前实现的具体优势时,这个子技能才会标记此类语句。如果发现只能给出“此处可考虑使用某种模式”这类泛泛建议,而无法指出具体模式,则应交由 SOLID 审查器处理。为避免重复发现,请检查同一个switch/if-else代码块是否已涵盖在 OCP 违规中。如果codeprobe-solid会标记该问题,而你的建议只是“使用多态”,则不要生成发现项。 **判定规则:**如果你能指出模式名称、展示接口并列出具体实现,则生成PATTERN-发现项。如果你只能说“这违反了 OCP”,则交由codeprobe-solid处理。 -
上帝类已由
codeprobe-architecture(ARCH-xxx)标记。 只有在推荐采用某种具体模式(例如 Facade、Mediator)作为拆分方式时,这个子技能才会标记此类问题。如果建议只是“拆分此类”,则应交由架构审查器处理。只有在能够指出确切模式,并解释为何它比泛泛的拆分类方案更合适时,才生成发现项。 **判定规则:**如果修复提示是“提取为具有这些方法的 Facade”,则生成PATTERN-发现项。如果提示是“将其拆分为更小的类”,则交由codeprobe-architecture处理。 -
由
codeprobe-code-smells(SMELL-xxx)标记的横切关注点。 重复的日志记录、缓存或授权代码可能已作为代码重复问题被标记。只有在建议采用某种具体模式(Decorator、Middleware)作为解决方案时,才生成PATTERN-发现项。如果主要问题是重复,则交由代码异味审查器处理。 -
简单脚本或小型应用中,使用模式会造成过度设计。一个 50 行的 CLI 脚本不需要 Strategy 模式。单文件工具不需要 Factory。应根据实际情况判断设计是否适度——模式是管理复杂度的工具,而非目的本身。
-
已正确实现某种模式的代码——不要建议用另一种正确模式替换现有模式。如果 Factory 运行良好,就不要建议改用 Builder,除非存在具体问题。如果某个类正确使用了 Observer,就不要建议改用 Mediator。
-
测试文件——测试工具和辅助程序有不同的设计约束。测试设置类、fixture 构建器和 mock 工厂不适用与生产代码相同的模式要求。不要标记测试替身、测试数据构建器或测试编排辅助程序。
-
置信度较低的模式匹配(例如 Prototype 模式),除非有充分证据表明存在克隆行为。严重级别最高只能标为 Suggestion。如有疑问,不要生成发现项。
检测说明
模式机会
| 观察到的问题 | 候选模式 | 检测方式 | 置信度 | 严重程度 |
|---|---|---|---|---|
| 构造复杂对象时有 4 个以上可选参数 | Builder | 构造函数或工厂方法有 4 个以上可选/可空参数。使用 setter 逐步构建对象,最后调用 build() 的方法会更清晰。 | 高 | 轻微 |
代码库中散布着重复的 new X() 和条件判断 | Factory | 搜索同一类对象在 3 个以上位置通过 new ClassName() 实例化,且周围有用于决定创建哪个类的 if/switch 逻辑。 | 高 | 严重 |
| 根据类型切换行为(适用于特定模式时) | Strategy | Switch/if-else 链的每个分支都会执行不同的算法或行为,而不只是返回一个值。必须有 3 个以上分支,且变体很可能会增加。只有在尚未被 OCP 发现覆盖时才标记。 | 高 | 严重 |
| 对象行为根据内部状态字段变化 | State | 类中的方法包含针对 $this->status 或 this.state 的 if/switch,且同一字段在 3 个以上方法中控制行为。状态转换散布在类中。 | 中 | 轻微 |
| 多个监听器需要响应变化 | Observer / Event Dispatcher | 状态变化后,某个方法会直接调用 3 个以上其他服务/处理器(例如,创建订单后发送邮件、更新库存、通知仓库、记录审计日志)。此处应使用事件。 | 高 | 轻微 |
| 横切逻辑与业务逻辑交织在一起 | Decorator / Middleware | 日志记录、缓存、授权或计时逻辑混杂在业务逻辑方法中。相同的横切关注点在 3 个以上方法中被复制粘贴。 | 高 | 严重 |
| 包装复杂子系统的上帝类 | Facade | 一个协调多个子系统的大型类(300 行以上代码)。客户端只需要简化后的接口。只有在 probe-architecture 尚未将其标记为上帝对象时才标记。 | 中 | 轻微 |
| 有撤销/重做或命令队列需求 | Command | 代码需要对操作进行排队、记录或撤销,但目前是内联执行。 | 中 | 建议 |
| 数据经过条件式转换步骤流转 | Pipeline / Chain of Responsibility | 数据经过 3 个以上顺序执行的 if/else 转换步骤处理,且每个步骤都按条件应用。可以使用由可组合阶段构成的流水线。 | 中 | 轻微 |
| 多个相似对象仅有少数字段不同 | Prototype | 类似工厂的代码会创建对象副本,仅存在细微差异。 | 低 | 建议 |
反模式(误用模式)
| 反模式 | 检测内容 | 检测方法 | 严重程度 |
|---|---|---|---|
| 用单例隐藏依赖 | 类通过 getInstance()、static::$instance 或模块级单例访问本应通过构造函数注入的依赖。单例模式会隐藏依赖,并增加测试难度。 | 在业务逻辑类中搜索 getInstance()、static::$instance、self::$instance 及模块级单例访问模式。检查这些依赖是否可以改为通过构造函数注入。 | 重大 |
| 透传型 Repository | Repository 类包装 ORM(Eloquent、Doctrine、Prisma),且每个方法都只是 1 行委托,不增加任何抽象、缓存或查询逻辑。该 Repository 增加了一层却没有价值。 | 找出 Repository 类并检查每个公共方法的主体:如果所有方法都只是单行调用底层 ORM 模型,且没有额外逻辑,那么该 Repository 就是透传型 Repository。 | 次要 |
| 只是改名后的控制器操作的服务类 | 服务类只有一个公共方法,且与某个控制器操作完全一致——参数相同、逻辑相同,只是移到了另一个文件中。这会增加间接层,却没有带来复用。 | 找出只有一个公共方法的服务类。检查该方法的签名和逻辑是否与相应的控制器操作高度相似。查看代码库中是否完全没有复用(只有一个调用方)。 | 次要 |
| 只有一个产品族的抽象工厂 | 抽象工厂接口只有一个具体工厂实现,且没有可预见的第二种实现。属于过度抽象。 | 找出抽象工厂接口/类,并统计具体实现的数量。如果恰好只有一个实现,且没有计划扩展的迹象(没有 TODO 注释,也没有文档提及未来的变体),则标记该问题。 | 建议 |
ID 前缀与修复提示词示例
所有发现的问题都使用 PATTERN- 前缀,并按顺序编号:PATTERN-001、PATTERN-002 等。
修复提示词示例
- “将
NotificationSender中针对$type的 switch(第 30-65 行)替换为策略模式:创建一个包含send(Message $message)方法的NotificationChannel接口。创建EmailChannel、SmsChannel和PushChannel实现。使用NotificationChannelFactory按类型解析正确的通道。” - “重构
ReportBuilder构造函数(第 15 行):它接收 7 个可选参数($title、$subtitle、$dateRange、$format、$includeCharts、$paperSize、$orientation),将其改为 Builder 模式:创建ReportBuilderConfig,提供链式 setter 方法和build()方法。” - “
app/Services/AuditLogger.php中的AuditLogger使用AuditLogger::getInstance()(第 5 行)实现单例。改为构造函数注入:在 DI 容器中将AuditLogger注册为单例绑定,并通过构造函数将其注入当前调用::getInstance()的 4 个类中。” - “移除
app/Repositories/下的UserRepositoryInterface和UserRepository封装类——每个方法(find、create、update、delete)都只是单行委托给 Eloquent,没有增加任何逻辑。在有具体理由需要抽象之前,直接使用 Eloquent 模型。”