SOLID原则
High Contrast
Dark Mode
Light Mode
Sepia
Forest
3 min read613 words

SOLID原则

SOLID是面向对象设计的五大基本原则,是设计模式的理论基础。理解这些原则有助于你判断何时使用设计模式。

SOLID概述

SOLID由Robert C. Martin(Uncle Bob)在2000年代初提出,是编写可维护、可扩展软件的核心原则。

graph TB A[SOLID原则] --> B[S - Single Responsibility] A --> C[O - Open/Closed] A --> D[L - Liskov Substitution] A --> E[I - Interface Segregation] A --> F[D - Dependency Inversion] B --> B1[单一职责原则] C --> C1[开闭原则] D --> D1[里氏替换原则] E --> E1[接口隔离原则] F --> F1[依赖倒置原则] style A fill:#ede7f6,stroke:#5e35b1,stroke-width:3px style B fill:#e3f2fd,stroke:#1976d2,stroke-width:2px style C fill:#e3f2fd,stroke:#1976d2,stroke-width:2px style D fill:#e3f2fd,stroke:#1976d2,stroke-width:2px style E fill:#e3f2fd,stroke:#1976d2,stroke-width:2px style F fill:#e3f2fd,stroke:#1976d2,stroke-width:2px

S - 单一职责原则(Single Responsibility Principle)

定义

一个类应该只有一个引起它变化的原因。

❌ 违反SRP的例子

class User:
"""违反单一职责原则"""
def __init__(self, name, email):
self.name = name
self.email = email
def save_to_database(self):
"""保存到数据库"""
print(f"保存用户 {self.name} 到数据库")
def send_email(self, subject, message):
"""发送邮件"""
print(f"发送邮件到 {self.email}:{subject}")
def validate_email(self):
"""验证邮箱"""
return "@" in self.email
def generate_report(self):
"""生成报告"""
return f"用户报告:{self.name}"

问题User 类承担了太多职责: - 用户数据管理 - 数据库操作 - 邮件发送 - 邮箱验证 - 报告生成

✅ 符合SRP的重构

class User:
"""只负责用户数据"""
def __init__(self, name, email):
self.name = name
self.email = email
class UserRepository:
"""负责数据库操作"""
def save(self, user):
print(f"保存用户 {user.name} 到数据库")
class EmailService:
"""负责邮件发送"""
def send(self, to_email, subject, message):
print(f"发送邮件到 {to_email}:{subject}")
class EmailValidator:
"""负责邮箱验证"""
@staticmethod
def validate(email):
return "@" in email
class ReportGenerator:
"""负责报告生成"""
def generate_user_report(self, user):
return f"用户报告:{user.name}"
# 使用
user = User("张三", "zhangsan@example.com")
if EmailValidator.validate(user.email):
repo = UserRepository()
repo.save(user)
email_service = EmailService()
email_service.send(user.email, "欢迎", "欢迎注册!")

O - 开闭原则(Open/Closed Principle)

定义

软件实体应该对扩展开放,对修改关闭。

❌ 违反OCP的例子

class OrderCalculator:
"""订单计算器"""
def calculate(self, order_type, amount):
if order_type == "normal":
return amount
elif order_type == "vip":
return amount * 0.9
elif order_type == "svip":
return amount * 0.8
# 每次新增用户类型都要修改这个方法
elif order_type == "premium":
return amount * 0.7

✅ 符合OCP的重构

from abc import ABC, abstractmethod
class DiscountStrategy(ABC):
"""折扣策略抽象类"""
@abstractmethod
def calculate(self, amount):
pass
class NormalDiscount(DiscountStrategy):
"""普通用户"""
def calculate(self, amount):
return amount
class VIPDiscount(DiscountStrategy):
"""VIP用户"""
def calculate(self, amount):
return amount * 0.9
class SVIPDiscount(DiscountStrategy):
"""超级VIP用户"""
def calculate(self, amount):
return amount * 0.8
# 新增用户类型无需修改原有代码
class PremiumDiscount(DiscountStrategy):
"""高级用户"""
def calculate(self, amount):
return amount * 0.7
class OrderCalculator:
"""订单计算器"""
def __init__(self, discount_strategy: DiscountStrategy):
self.discount_strategy = discount_strategy
def calculate(self, amount):
return self.discount_strategy.calculate(amount)
# 使用
normal_order = OrderCalculator(NormalDiscount())
vip_order = OrderCalculator(VIPDiscount())
premium_order = OrderCalculator(PremiumDiscount())  # 新增类型,无需修改
print(normal_order.calculate(100))    # 100
print(vip_order.calculate(100))      # 90
print(premium_order.calculate(100))  # 70

L - 里氏替换原则(Liskov Substitution Principle)

定义

子类必须能够替换父类,而不影响程序的正确性。

❌ 违反LSP的例子

class Rectangle:
"""矩形"""
def __init__(self, width, height):
self.width = width
self.height = height
def set_width(self, width):
self.width = width
def set_height(self, height):
self.height = height
def area(self):
return self.width * self.height
class Square(Rectangle):
"""正方形 - 继承矩形"""
def set_width(self, width):
self.width = width
self.height = width  # 正方形长宽相等
def set_height(self, height):
self.height = height
self.width = height  # 正方形长宽相等
# 问题:用正方形替换矩形会出问题
def process_rectangle(rect: Rectangle):
rect.set_width(5)
rect.set_height(4)
# 期望面积 = 5 * 4 = 20
print(f"面积:{rect.area()}")  # 但正方形输出 = 4 * 4 = 16
rect = Rectangle(0, 0)
process_rectangle(rect)  # 面积:20 ✓
square = Square(0, 0)
process_rectangle(square)  # 面积:16 ✗ 违反了期望!

✅ 符合LSP的重构

from abc import ABC, abstractmethod
class Shape(ABC):
"""形状基类"""
@abstractmethod
def area(self):
pass
class Rectangle(Shape):
"""矩形"""
def __init__(self, width, height):
self.width = width
self.height = height
def set_width(self, width):
self.width = width
def set_height(self, height):
self.height = height
def area(self):
return self.width * self.height
class Square(Shape):
"""正方形 - 不继承矩形"""
def __init__(self, side):
self.side = side
def set_side(self, side):
self.side = side
def area(self):
return self.side * self.side
# 现在两个类都可以安全地作为Shape使用
def get_area(shape: Shape):
return shape.area()
print(get_area(Rectangle(5, 4)))  # 20
print(get_area(Square(5)))        # 25

I - 接口隔离原则(Interface Segregation Principle)

定义

客户端不应该依赖它不需要的接口。

❌ 违反ISP的例子

class Printer(ABC):
"""打印机接口 - 过于庞大"""
@abstractmethod
def print(self, document):
pass
@abstractmethod
def scan(self, document):
pass
@abstractmethod
def fax(self, document):
pass
@abstractmethod
def copy(self, document):
pass
class SimplePrinter(Printer):
"""简单的打印机 - 只能打印"""
def print(self, document):
print(f"打印:{document}")
def scan(self, document):
raise NotImplementedError("不支持扫描")
def fax(self, document):
raise NotImplementedError("不支持传真")
def copy(self, document):
raise NotImplementedError("不支持复印")

✅ 符合ISP的重构

from abc import ABC, abstractmethod
class IPrinter(ABC):
"""打印接口"""
@abstractmethod
def print(self, document):
pass
class IScanner(ABC):
"""扫描接口"""
@abstractmethod
def scan(self, document):
pass
class IFax(ABC):
"""传真接口"""
@abstractmethod
def fax(self, document):
pass
class ICopier(ABC):
"""复印接口"""
@abstractmethod
def copy(self, document):
pass
class SimplePrinter(IPrinter):
"""简单打印机 - 只实现打印"""
def print(self, document):
print(f"打印:{document}")
class MultiFunctionPrinter(IPrinter, IScanner, IFax, ICopier):
"""多功能打印机 - 实现所有接口"""
def print(self, document):
print(f"打印:{document}")
def scan(self, document):
print(f"扫描:{document}")
def fax(self, document):
print(f"传真:{document}")
def copy(self, document):
print(f"复印:{document}")
# 使用
simple = SimplePrinter()
simple.print("文档")  # 只使用需要的功能
multi = MultiFunctionPrinter()
multi.print("文档")
multi.scan("文档")

D - 依赖倒置原则(Dependency Inversion Principle)

定义

❌ 违反DIP的例子

class MySQLDatabase:
"""MySQL数据库"""
def save(self, data):
print(f"保存到MySQL:{data}")
class UserService:
"""用户服务 - 直接依赖具体实现"""
def __init__(self):
self.database = MySQLDatabase()  # 强依赖MySQL
def save_user(self, user):
self.database.save(user)

问题:如果要换成PostgreSQL或MongoDB,需要修改UserService类。

✅ 符合DIP的重构

from abc import ABC, abstractmethod
class IDatabase(ABC):
"""数据库抽象接口"""
@abstractmethod
def save(self, data):
pass
class MySQLDatabase(IDatabase):
"""MySQL实现"""
def save(self, data):
print(f"保存到MySQL:{data}")
class PostgreSQLDatabase(IDatabase):
"""PostgreSQL实现"""
def save(self, data):
print(f"保存到PostgreSQL:{data}")
class MongoDB(IDatabase):
"""MongoDB实现"""
def save(self, data):
print(f"保存到MongoDB:{data}")
class UserService:
"""用户服务 - 依赖抽象,不依赖具体实现"""
def __init__(self, database: IDatabase):
self.database = database
def save_user(self, user):
self.database.save(user)
# 使用:轻松切换数据库
mysql_service = UserService(MySQLDatabase())
postgres_service = UserService(PostgreSQLDatabase())
mongo_service = UserService(MongoDB())
mysql_service.save_user("张三")      # 保存到MySQL
postgres_service.save_user("李四")   # 保存到PostgreSQL
mongo_service.save_user("王五")     # 保存到MongoDB

SOLID原则总结

graph TB A[SOLID原则] --> B[SRP] A --> C[OCP] A --> D[LSP] A --> E[ISP] A --> F[DIP] B --> B1[一个类只负责一件事] C --> C1[对扩展开放,对修改关闭] D --> D1[子类可以替换父类] E --> E1[不依赖不需要的接口] F --> F1[依赖抽象,不依赖具体] style A fill:#ede7f6,stroke:#5e35b1,stroke-width:3px style B fill:#e3f2fd,stroke:#1976d2,stroke-width:2px style C fill:#fff9c4,stroke:#f9a825,stroke-width:2px style D fill:#c8e6c9,stroke:#43a047,stroke-width:2px style E fill:#fce4ec,stroke:#c2185b,stroke-width:2px style F fill:#a5d6a7,stroke:#2e7d32,stroke-width:2px

实际应用:一个完整示例

让我们用SOLID原则重构一个订单处理系统。

❌ 初始版本(违反多个原则)

class OrderProcessor:
"""订单处理器 - 违反多个SOLID原则"""
def process(self, order):
# 计算折扣
if order.type == "normal":
total = order.amount
elif order.type == "vip":
total = order.amount * 0.9
# 发送邮件
import smtplib
# ... 大量邮件发送代码
# 保存到数据库
# ... 大量数据库代码
# 生成报告
# ... 大量报告生成代码

✅ 重构后(符合SOLID)

# 1. 单一职责原则:每个类只做一件事
class Order:
def __init__(self, order_type, amount, email):
self.type = order_type
self.amount = amount
self.email = email
# 2. 开闭原则 + 3. 里氏替换原则:使用抽象类
class DiscountStrategy(ABC):
@abstractmethod
def calculate(self, amount):
pass
class NormalDiscount(DiscountStrategy):
def calculate(self, amount):
return amount
class VIPDiscount(DiscountStrategy):
def calculate(self, amount):
return amount * 0.9
# 4. 接口隔离原则:精简的接口
class IEmailService(ABC):
@abstractmethod
def send(self, to, subject, message):
pass
class EmailService(IEmailService):
def send(self, to, subject, message):
print(f"发送邮件到 {to}:{subject}")
class IDatabase(ABC):
@abstractmethod
def save(self, data):
pass
class Database(IDatabase):
def save(self, data):
print(f"保存数据:{data}")
# 5. 依赖倒置原则:依赖抽象
class OrderProcessor:
def __init__(
self,
discount_strategy: DiscountStrategy,
email_service: IEmailService,
database: IDatabase
):
self.discount_strategy = discount_strategy
self.email_service = email_service
self.database = database
def process(self, order: Order):
# 计算折扣
total = self.discount_strategy.calculate(order.amount)
# 发送邮件
self.email_service.send(order.email, "订单确认", f"总金额:{total}")
# 保存数据
self.database.save({"type": order.type, "total": total})
return total
# 使用
normal_processor = OrderProcessor(
NormalDiscount(),
EmailService(),
Database()
)
vip_processor = OrderProcessor(
VIPDiscount(),
EmailService(),
Database()
)
normal_order = Order("normal", 100, "user1@example.com")
vip_order = Order("vip", 100, "user2@example.com")
print(normal_processor.process(normal_order))  # 100
print(vip_processor.process(vip_order))       # 90

SOLID与设计模式

设计模式是SOLID原则的具体应用:

设计模式 主要应用的SOLID原则
策略模式 OCP, DIP
工厂方法模式 OCP, DIP
观察者模式 ISP
装饰器模式 OCP
适配器模式 ISP

本章要点


下一步学习指南 🚀