全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-19 10 分钟 ✍️ juanwangdev

Python SOLID原则实践

SOLID是面向对象设计的五大原则,是编写可维护代码的基础。

单一职责原则(SRP)

原则定义

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

违反SRP示例

Python
# 违反SRP:一个类承担多种职责
class UserManager:
    def __init__(self, db):
        self.db = db

    # 用户数据管理职责
    def create_user(self, name, email):
        user = User(name, email)
        self.db.save(user)

    def get_user(self, user_id):
        return self.db.query(User).get(user_id)

    # 用户验证职责
    def validate_email(self, email):
        return '@' in email

    def validate_name(self, name):
        return len(name) > 0

    # 邮件发送职责
    def send_welcome_email(self, user):
        email_body = f"Welcome {user.name}!"
        self.email_client.send(user.email, email_body)

    # 日志记录职责
    def log_user_creation(self, user):
        self.logger.info(f"User created: {user.id}")

    # 报告生成职责
    def generate_user_report(self, user_id):
        user = self.get_user(user_id)
        return self.report_generator.create_report(user)

符合SRP重构

Python
# 每个类只有一个职责

# 用户数据管理
class UserRepository:
    def __init__(self, db):
        self.db = db

    def save(self, user):
        self.db.add(user)

    def find(self, user_id):
        return self.db.query(User).get(user_id)

# 用户验证
class UserValidator:
    def validate(self, name, email):
        errors = []
        if not self._validate_name(name):
            errors.append("Invalid name")
        if not self._validate_email(email):
            errors.append("Invalid email")
        return errors

    def _validate_name(self, name):
        return len(name) > 0

    def _validate_email(self, email):
        return '@' in email

# 邮件服务
class EmailService:
    def __init__(self, email_client):
        self.client = email_client

    def send_welcome(self, user):
        body = f"Welcome {user.name}!"
        self.client.send(user.email, body)

# 用户服务(协调者)
class UserService:
    def __init__(self, repository, validator, email_service):
        self.repo = repository
        self.validator = validator
        self.email = email_service

    def create_user(self, name, email):
        errors = self.validator.validate(name, email)
        if errors:
            raise ValueError(errors)

        user = User(name, email)
        self.repo.save(user)
        self.email.send_welcome(user)
        return user

开放封闭原则(OCP)

原则定义

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

违反OCP示例

Python
# 违反OCP:添加新类型需要修改现有代码
class PaymentProcessor:
    def process(self, payment_type, amount):
        if payment_type == 'credit_card':
            return self._process_credit_card(amount)
        elif payment_type == 'paypal':
            return self._process_paypal(amount)
        elif payment_type == 'bank_transfer':
            return self._process_bank_transfer(amount)
        # 添加新支付方式需要修改此方法

    def _process_credit_card(self, amount):
        pass

    def _process_paypal(self, amount):
        pass

    def _process_bank_transfer(self, amount):
        pass

符合OCP重构

Python
# 使用策略模式,添加新支付方式不修改现有代码

from abc import ABC, abstractmethod

# 抽象支付策略
class PaymentStrategy(ABC):
    @abstractmethod
    def process(self, amount):
        pass

# 具体策略实现
class CreditCardPayment(PaymentStrategy):
    def __init__(self, card_number, cvv):
        self.card_number = card_number
        self.cvv = cvv

    def process(self, amount):
        # 信用卡处理逻辑
        return {'status': 'success', 'method': 'credit_card'}

class PayPalPayment(PaymentStrategy):
    def __init__(self, email):
        self.email = email

    def process(self, amount):
        # PayPal处理逻辑
        return {'status': 'success', 'method': 'paypal'}

class BankTransferPayment(PaymentStrategy):
    def process(self, amount):
        return {'status': 'success', 'method': 'bank_transfer'}

# 新增支付方式,只需添加新类,无需修改PaymentProcessor
class AlipayPayment(PaymentStrategy):
    def process(self, amount):
        return {'status': 'success', 'method': 'alipay'}

# 处理器
class PaymentProcessor:
    def process(self, strategy: PaymentStrategy, amount):
        return strategy.process(amount)

# 使用
processor = PaymentProcessor()
result = processor.process(CreditCardPayment('1234', '123'), 100)

里氏替换原则(LSP)

原则定义

子类必须能够替换其基类而不影响程序正确性。

违反LSP示例

Python
# 违反LSP:子类行为与基类不一致
class Bird:
    def fly(self):
        return "Flying"

class Sparrow(Bird):
    def fly(self):
        return "Sparrow flying"

class Penguin(Bird):
    def fly(self):
        raise Exception("Penguins can't fly!")  # 违反LSP

def make_bird_fly(bird: Bird):
    bird.fly()  # Penguin会抛异常

make_bird_fly(Penguin())  # 出错

符合LSP重构

Python
# 重新设计继承层次

class Bird:
    def move(self):
        return "Moving"

class FlyingBird(Bird):
    def fly(self):
        return "Flying"

class SwimmingBird(Bird):
    def swim(self):
        return "Swimming"

class Sparrow(FlyingBird):
    def fly(self):
        return "Sparrow flying"

class Penguin(SwimmingBird):
    def swim(self):
        return "Penguin swimming"

def make_bird_move(bird: Bird):
    bird.move()  # 所有鸟类都能移动

make_bird_move(Penguin())  # 正常工作

接口隔离原则(ISP)

原则定义

客户端不应该依赖它不使用的接口。

违反ISP示例

Python
# 违反ISP:接口过于庞大
class Worker(ABC):
    @abstractmethod
    def work(self):
        pass

    @abstractmethod
    def eat(self):
        pass

    @abstractmethod
    def sleep(self):
        pass

class HumanWorker(Worker):
    def work(self):
        print("Working")

    def eat(self):
        print("Eating")

    def sleep(self):
        print("Sleeping")

class RobotWorker(Worker):
    def work(self):
        print("Working")

    def eat(self):
        raise Exception("Robot doesn't eat")  # 不需要但必须实现

    def sleep(self):
        raise Exception("Robot doesn't sleep")  # 不需要但必须实现

符合ISP重构

Python
# 接口分离,各取所需

class Workable(ABC):
    @abstractmethod
    def work(self):
        pass

class Feedable(ABC):
    @abstractmethod
    def eat(self):
        pass

class Sleepable(ABC):
    @abstractmethod
    def sleep(self):
        pass

class HumanWorker(Workable, Feedable, Sleepable):
    def work(self):
        print("Working")

    def eat(self):
        print("Eating")

    def sleep(self):
        print("Sleeping")

class RobotWorker(Workable):  # 只实现需要的接口
    def work(self):
        print("Working")

# 机器人不需要eat和sleep接口

依赖反转原则(DIP)

原则定义

高层模块不应依赖低层模块,两者都应依赖抽象。

违反DIP示例

Python
# 违反DIP:高层模块直接依赖低层模块
class UserService:
    def __init__(self):
        # 直接依赖具体实现
        self.db = MySQLDatabase()
        self.logger = FileLogger()
        self.email = SMTPClient()

    def create_user(self, name, email):
        user = User(name, email)
        self.db.save(user)
        self.logger.log(f"Created user {name}")
        self.email.send(email, "Welcome!")

# 切换数据库或日志系统需要修改UserService

符合DIP重构

Python
# 高层模块依赖抽象接口

from abc import ABC, abstractmethod

# 抽象接口
class Database(ABC):
    @abstractmethod
    def save(self, entity):
        pass

    @abstractmethod
    def find(self, entity_id):
        pass

class Logger(ABC):
    @abstractmethod
    def log(self, message):
        pass

class EmailSender(ABC):
    @abstractmethod
    def send(self, to, message):
        pass

# 具体实现
class MySQLDatabase(Database):
    def save(self, entity):
        pass

    def find(self, entity_id):
        pass

class PostgreSQLDatabase(Database):
    def save(self, entity):
        pass

    def find(self, entity_id):
        pass

class FileLogger(Logger):
    def log(self, message):
        pass

# 高层模块依赖抽象
class UserService:
    def __init__(self, db: Database, logger: Logger, email: EmailSender):
        self.db = db      # 依赖抽象,可替换任何实现
        self.logger = logger
        self.email = email

    def create_user(self, name, email):
        user = User(name, email)
        self.db.save(user)
        self.logger.log(f"Created user {name}")
        self.email.send(email, "Welcome!")

# 依赖注入
service = UserService(
    PostgreSQLDatabase(),
    FileLogger(),
    SMTPClient()
)

SOLID原则综合应用

完整示例

Python
from abc import ABC, abstractmethod
from typing import List

# 抽象层(DIP)
class NotificationChannel(ABC):
    @abstractmethod
    def send(self, recipient: str, message: str) -> bool:
        pass

class NotificationTemplate(ABC):
    @abstractmethod
    def render(self, data: dict) -> str:
        pass

# 具体实现(OCP扩展)
class EmailChannel(NotificationChannel):
    def __init__(self, smtp_client):
        self.client = smtp_client

    def send(self, recipient, message):
        return self.client.send_email(recipient, message)

class SMSChannel(NotificationChannel):
    def send(self, recipient, message):
        return self.sms_client.send_sms(recipient, message)

class WelcomeTemplate(NotificationTemplate):
    def render(self, data):
        return f"Welcome {data['name']}!"

# 单一职责(SRP)
class NotificationSender:
    def __init__(self, channel: NotificationChannel):
        self.channel = channel

    def send(self, recipient, message):
        return self.channel.send(recipient, message)

class NotificationComposer:
    def __init__(self, template: NotificationTemplate):
        self.template = template

    def compose(self, data):
        return self.template.render(data)

# 服务协调
class NotificationService:
    def __init__(self, sender: NotificationSender, composer: NotificationComposer):
        self.sender = sender      # 依赖抽象(DIP)
        self.composer = composer

    def notify(self, recipient, data):
        message = self.composer.compose(data)
        return self.sender.send(recipient, message)

SOLID原则对比

原则关注点核心规则
SRP类的职责一个类只有一个变化原因
OCP扩展性对扩展开放,对修改关闭
LSP继承子类可完全替换父类
ISP接口设计接口要小而专
DIP依赖关系依赖抽象而非具体

注意:SOLID原则要灵活应用,过度遵守会增加复杂度,根据实际场景平衡取舍。

要点总结

  • SRP:一个类只有一个职责,变化原因单一,拆分大类
  • OCP:通过抽象和策略模式实现扩展开放、修改关闭
  • LSP:子类行为与父类一致,继承层次合理,不违反父类契约
  • ISP:接口要小而专,客户端只依赖需要的接口
  • DIP:高层依赖抽象接口,通过依赖注入传入具体实现

存放路径articles/PYTHON/专家/架构与设计/SOLID原则实践.md

📝 发现内容有误?点击此处直接编辑

← 上一篇 Python API设计最佳实践
下一篇 → Python代码重构技术
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库