solid

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SOLID Principles

SOLID原则

Five core principles of object-oriented design that lead to systems which are simpler to maintain, test, and extend. Robert C. Martin (Uncle Bob) formalized these ideas, and Michael Feathers coined the SOLID acronym.
面向对象设计的五大核心原则,遵循这些原则可以让系统更易于维护、测试和扩展。这些理念由Robert C. Martin(鲍勃大叔)正式提出,Michael Feathers创造了SOLID这个首字母缩写。

Principle Index

原则索引

PrincipleSummaryReference
S — Single ResponsibilityA class should have only one reason to changereference
O — Open/ClosedOpen for extension, closed for modificationreference
L — Liskov SubstitutionSubtypes must be substitutable for their base typesreference
I — Interface SegregationPrefer many specific interfaces over one general-purpose interfacereference
D — Dependency InversionDepend on abstractions, not concretionsreference
原则概述参考资料
S — 单一职责原则一个类应该只有一个变更的理由reference
O — 开闭原则对扩展开放,对修改关闭reference
L — 里氏替换原则子类型必须能够替换它们的基类型reference
I — 接口隔离原则优先使用多个专用接口,而非一个通用接口reference
D — 依赖倒置原则依赖抽象,而非具体实现reference

Why SOLID Matters

SOLID的重要性

Without SOLID, codebases gradually develop these problems:
  • Rigidity — one change ripples through many unrelated modules
  • Fragility — modifying one area breaks another seemingly unconnected area
  • Immobility — components are so intertwined that extracting them for reuse is impractical
  • Viscosity — doing things correctly is harder than hacking around the design
SOLID tackles each of these by defining clear boundaries, explicit contracts, and flexible points for extension.
如果不遵循SOLID原则,代码库会逐渐出现以下问题:
  • 僵化:一处改动会波及大量不相关的模块
  • 脆弱:修改某部分代码会破坏另一个看似无关的模块
  • 难以复用:组件之间耦合度过高,几乎无法提取出来复用
  • 粘滞性:遵循正确的开发方式比绕过设计写临时代码难度更高
SOLID通过定义清晰的边界、明确的契约和灵活的扩展点来解决以上所有问题。

Quick Decision Guide

快速决策指南

SymptomLikely Violated PrincipleFix
Class does too many thingsSRPSplit into focused classes
Adding a feature requires editing existing classesOCPIntroduce polymorphism or strategy
Subclass breaks when used in place of parentLSPFix inheritance hierarchy or use composition
Classes forced to implement unused methodsISPBreak interface into smaller ones
High-level module imports low-level detailsDIPIntroduce an abstraction layer
症状可能违反的原则修复方案
类承担了过多职责SRP拆分为职责单一的类
添加新功能需要修改现有类OCP引入多态或策略模式
子类替换父类使用时出现异常LSP修复继承层级或改用组合模式
类被迫实现不需要的方法ISP将接口拆分为更小的专用接口
高层模块直接依赖底层实现细节DIP引入抽象层

Quick Examples

快速示例

SRP — Before and After

单一职责原则 — 改造前后对比

php
// 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 { /* ... */ }
}
php
// BEFORE: 类同时处理用户数据和邮件发送
class UserService {
    public function createUser(string $name, string $email): void { /* ... */ }
    public function sendWelcomeEmail(string $email): void { /* ... */ }
}

// AFTER: 每个类只承担一个职责
class UserService {
    public function __construct(private UserNotifier $notifier) {}
    public function createUser(string $name, string $email): void {
        // 持久化用户数据...
        $this->notifier->welcomeNewUser($email);
    }
}

class UserNotifier {
    public function welcomeNewUser(string $email): void { /* ... */ }
}

OCP — Extend Without Modifying

开闭原则 — 无需修改即可扩展

php
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);
    }
}
php
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;
    }
}

// 新增折扣类型无需修改现有代码
class FlatDiscount implements DiscountPolicy {
    public function __construct(private float $amount) {}
    public function calculate(float $total): float {
        return min($this->amount, $total);
    }
}

DIP — Depend on Abstractions

依赖倒置原则 — 依赖抽象

php
// 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);
    }
}
php
// 高层策略依赖抽象,而非数据库具体实现细节
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);
    }
}

Relationships Between Principles

原则之间的关联

The five principles complement and reinforce one another:
  • SRP + ISP: Both narrow the surface area of a class or interface to a single, focused concern
  • OCP + DIP: Abstractions are the mechanism that enables extension without modification
  • LSP + OCP: Correct substitutability is essential for polymorphic extension to work
  • ISP + DIP: Well-segregated interfaces make it easier to depend on precisely the right abstraction
五大原则相互补充、相互强化:
  • SRP + ISP:二者都要求缩小类或接口的暴露面,只聚焦于单一的核心职责
  • OCP + DIP:抽象是实现无需修改即可扩展的核心机制
  • LSP + OCP:正确的可替换性是多态扩展正常运行的必要前提
  • ISP + DIP:良好隔离的接口让开发者更容易依赖精准匹配需求的抽象

Common Misconceptions

常见误解

  • "One method per class" — SRP means one reason to change, not one method. A class can contain many methods as long as they all serve the same responsibility.
  • "Never modify existing code" — OCP does not prohibit bug fixes. It means new behavior should be introducible without changing existing working code.
  • "Always use interfaces" — DIP calls for depending on abstractions. Sometimes a well-crafted base class is the appropriate abstraction. Do not create interfaces for classes that will never have a second implementation.
  • "Inheritance is bad" — LSP does not discourage inheritance. It establishes rules for correct inheritance so that subtypes remain safely substitutable.
  • “每个类只能有一个方法”:SRP指的是只有一个变更理由,而非只能有一个方法。只要所有方法都服务于同一个职责,一个类可以包含多个方法。
  • “永远不要修改现有代码”:OCP并不禁止修复bug。它指的是可以在不修改现有可运行代码的前提下引入新功能。
  • “必须始终使用接口”:DIP要求依赖抽象,有时精心设计的基类就是合适的抽象。不要为永远不会有第二种实现的类创建接口。
  • “继承是不好的”:LSP并不反对使用继承,它为正确的继承制定了规则,确保子类型可以安全地替换父类型。

Best Practices

最佳实践

  • Adopt SOLID incrementally — do not refactor everything in one pass
  • Treat SOLID as a diagnostic tool: when code resists change, check which principle is being violated
  • Pair with design patterns — Strategy (OCP), Adapter (DIP), and Decorator (OCP) are direct implementations of SOLID ideas
  • Write tests first — TDD naturally steers designs toward SOLID compliance
  • Target PHP 8.3+ with strict typing, readonly classes, and enums
  • 逐步落地SOLID原则——不要一次性重构所有代码
  • 将SOLID作为诊断工具:当代码难以改动时,检查是否违反了相关原则
  • 结合设计模式使用——策略模式(OCP)、适配器模式(DIP)、装饰器模式(OCP)都是SOLID理念的直接实现
  • 优先编写测试——TDD(测试驱动开发)会自然引导设计符合SOLID规范
  • 推荐使用PHP 8.3+版本,配合严格类型、只读类和枚举特性