mcpField
S
solid

solid

github.com/krzysztofsurdy开发2968 次安装1 周前更新
代码仓库

关于 solid

讲解面向对象代码中五项 SOLID 原则的软件设计 Skill。帮助开发者诊断可维护性与扩展性问题,并选择有针对性的设计调整。

主要功能

  1. 01单一职责原则指导
  2. 02开闭原则的扩展指导
  3. 03里氏替换原则检查
  4. 04接口隔离原则指导
  5. 05依赖倒置原则指导
  6. 06原则间关系与常见误解

适用场景

  1. 01诊断职责过多的类
  2. 02设计可扩展现有行为的功能
  3. 03检查继承关系与接口边界
  4. 04减少对具体实现细节的依赖

安装

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

$npx skills add https://github.com/krzysztofsurdy/code-virtuoso --skill solid

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
dip.md
isp.md
lsp.md
ocp.md
srp.md

详细介绍

SOLID 原则

面向对象设计的五项核心原则,能让系统更易于维护、测试和扩展。Robert C. Martin(Uncle Bob)系统阐述了这些理念,Michael Feathers 则创造了 SOLID 这个缩写。

原则索引

原则概述参考
S:单一职责一个类应该只有一个变更理由参考
O:开闭原则对扩展开放,对修改关闭参考
L:里氏替换子类型必须能够替代其基类型参考
I:接口隔离倾向于使用多个特定接口,而不是一个通用接口参考
D:依赖反转依赖抽象,而非具体实现参考

SOLID 为什么重要

没有 SOLID,代码库会逐渐出现以下问题:

  • 僵化:一处变更会波及许多无关模块
  • 脆弱:修改某个区域会导致另一个看似无关的区域出错
  • 难以复用:组件彼此交织得太紧密,难以将其提取出来复用
  • 黏滞性:正确实现比绕过设计走捷径更困难

SOLID 通过清晰的边界、明确的契约和定义好的扩展点来解决这些问题。

快速决策指南

症状可能违反的原则修复方法
类承担的职责过多SRP拆分为职责明确的类
添加功能需要修改现有类OCP引入多态或策略
子类被用来替代父类时出现问题LSP修正继承层次结构或改用组合
类被迫实现未使用的方法ISP将接口拆分为更小的接口
高层模块导入底层细节DIP引入抽象层

快速示例

SRP:改造前后
// BEFORE: Class handles both user data AND email sending
class UserService {
    public function createUser(string $name, string $email): void { /* ... */ }
    public function sendWelcomeEmail(string $email): void { /* ... */ }
}

// AFTER: Each class has one responsibility
class UserService {
    public function __construct(private UserNotifier $notifier) {}
    public function createUser(string $name, string $email): void {
        // persist user...
        $this->notifier->welcomeNewUser($email);
    }
}

class UserNotifier {
    public function welcomeNewUser(string $email): void { /* ... */ }
}
OCP:扩展而不修改
interface DiscountPolicy {
    public function calculate(float $total): float;
}

class PercentageDiscount implements DiscountPolicy {
    public function __construct(private float $rate) {}
    public function calculate(float $total): float {
        return $total * $this->rate;
    }
}

// Adding a new discount type requires NO changes to existing code
class FlatDiscount implements DiscountPolicy {
    public function __construct(private float $amount) {}
    public function calculate(float $total): float {
        return min($this->amount, $total);
    }
}
DIP:依赖抽象
// High-level policy depends on abstraction, not on database details
interface OrderRepository {
    public function save(Order $order): void;
}

class PlaceOrderHandler {
    public function __construct(private OrderRepository $repository) {}
    public function handle(PlaceOrderCommand $cmd): void {
        $order = Order::create($cmd->items);
        $this->repository->save($order);
    }
}

原则之间的关系

这五项原则相互促进:

  • SRP + ISP:两者都将类或接口的职责限定在单一关注点上
  • OCP + DIP:抽象使无需修改即可扩展成为可能
  • LSP + OCP:只有子类型能够正确替换基类型,多态扩展才有效
  • ISP + DIP:良好隔离的接口让依赖恰当的抽象变得更容易

常见误解

  • “一个类一个方法”:SRP 指的是只有一个变更理由,而不是只能有一个方法。只要方法都服务于同一职责,一个类可以有许多方法。
  • “绝不修改现有代码”:OCP 不禁止修复缺陷。它的意思是,添加新行为时应无需修改现有的可运行代码。
  • “始终使用接口”:DIP 要求依赖抽象。有时基类就是恰当的抽象。对于永远不会有第二种实现的类,不要创建接口。
  • “继承不好”:LSP 并不反对继承。它为正确的继承设定规则,确保子类型始终可以替换基类型。

最佳实践

  • 逐步采用 SOLID。不要一次性重构所有内容
  • 将 SOLID 视为诊断工具:当代码难以修改时,检查违反了哪项原则
  • 配合设计模式使用:Strategy(OCP)、Adapter(DIP)和 Decorator(OCP)都是 SOLID 理念的直接实现
  • 先编写测试。TDD 会引导设计符合 SOLID 原则
  • 使用语言提供的严格类型和不可变特性(readonly 或 final 字段、不可变值类型、枚举或密封类型),让编译器强制执行设计约束

评论

支持 Markdown