【设计模式】设计原则之单一职责原则

单一职责原则(SRP: Single Responsibility Principle)是 SOLID 设计原则中的基石,其核心目标是提升代码的可维护性降低耦合度。下面从原理、实践到 C++ 具体实现进行详细解析:


核心思想

一个类(或模块/函数)应该只有一个引起它变化的原因。​
即:​一个类只负责一项明确的职责

关键理解
  1. ​“职责”的界定​:指系统中可能独立变化的需求或功能维度
  2. ​“变化原因”​​:当需求变更时,修改代码的动机应只来源于单一业务逻辑
  3. 目标​:
    • 减少类之间的耦合
    • 提升代码复用性
    • 使代码更易理解、测试和维护

为何重要?—— 违反 SRP 的代价

// 🚫 典型违反 SRP 的 "上帝类" (God Class)
class FinancialReport {
public:
    void loadDataFromDatabase();     // 职责1:数据获取
    void parseDataToJSON();          // 职责2:数据解析
    void calculateRevenue();         // 职责3:业务计算
    void generatePDFReport();        // 职责4:报告生成
    void saveReportToCloud();        // 职责5:存储管理
};

问题分析​:

  • 修改数据源(如从数据库切为 API)需修改此类 ✅
  • 变更报表格式(PDF → Excel)需修改此类 ✅
  • 调整计算公式需修改此类 ✅
  • 后果​:任何需求的微小变更都可能引发连锁错误,测试难度剧增。

C++ 实现方案

1. 拆分职责为独立类
// ✅ 职责分离:每个类专注单一任务
class DataLoader {
public:
    virtual std::string loadData() const = 0; // 抽象数据源
};

class DatabaseLoader : public DataLoader { ... };
class APILoader : public DataLoader { ... };

class DataParser {
public:
    virtual JSON parse(const std::string& rawData) const;
};

class RevenueCalculator {
public:
    double calculate(const JSON& data) const;
};

class ReportGenerator {
public:
    virtual void generate(const JSON& data, const std::string& format) const;
};

class CloudStorage {
public:
    void upload(const std::string& reportPath) const;
};
2. 高层类通过组合协调
class FinancialReportService {
public:
    FinancialReportService(
        DataLoader& loader, 
        ReportGenerator& generator,
        CloudStorage& storage
    ) : loader_(loader), generator_(generator), storage_(storage) {}

    void runReport() {
        auto rawData = loader_.loadData();
        JSON parsedData = parser_.parse(rawData);
        double revenue = calculator_.calculate(parsedData);
        std::string report = generator_.generate(parsedData, "PDF");
        storage_.upload(report);
    }

private:
    DataLoader& loader_;          // 依赖抽象接口
    DataParser parser_;
    RevenueCalculator calculator_;
    ReportGenerator& generator_;
    CloudStorage& storage_;
};

SRP 应用场景与技巧

  1. 类的设计

    • 如果一个类同时处理数据持久化业务逻辑​ → 拆分为 Repository + Service
    • 如果一个类既解析输入渲染输出​ → 拆分为 Parser + Renderer
  2. 函数的设计

    // 🚫 违反 SRP
    void processUser(User& user) {
        if (!validate(user)) throw ...; // 验证
        encryptPassword(user);          // 加密
        db.save(user);                 // 存储
        sendWelcomeEmail(user);        // 通知
    }
    
    // ✅ 拆分职责
    void processUser(User& user) {
        UserValidator::validate(user);   // 验证职责剥离
        UserProcessor::process(user);    // 处理核心逻辑
        Notifier::sendWelcome(user);     // 通知职责剥离
    }
  3. 模块层面的 SRP

    • 将日志记录、配置管理、异常处理等功能抽离为独立模块。

衡量是否遵守 SRP 的实用标准

  1. ​“AND” 测试法
    描述类职责时是否出现 ​​“且”​​ 字?

    ❌ “此类负责加载数据且生成报告” → 违反 SRP
    ✅ “此类负责加载数据” → 符合 SRP

  2. 变更影响评估
    当某个需求变更时,是否只需修改一个类​?

  3. 测试难易度
    是否能对每个职责进行独立单元测试​?


C++ 特殊优化策略

  1. 利用 PIMPL 隐藏实现细节

    // 头文件: ReportGenerator.h
    class ReportGenerator {
    public:
        ReportGenerator();
        ~ReportGenerator();
        void generate(const JSON& data);
    private:
        class Impl;  // 前向声明
        std::unique_ptr<Impl> pimpl_; // 实现与接口物理隔离
    };
    
    // 源文件: ReportGenerator.cpp
    class ReportGenerator::Impl {
        // 具体实现可自由修改, 不影响头文件依赖
        void generateImpl(const JSON& data) { ... }
    };
    ReportGenerator::generate(const JSON& data) {
        pimpl_->generateImpl(data);
    }
  2. 依赖注入解耦
    通过构造函数传入依赖对象(如前述 FinancialReportService),避免内部实例化具体实现。


总结

场景违反 SRP遵循 SRP
需求变更需修改同一类的多处仅修改一个类
代码复用难复用臃肿类可单独复用小类
可测试性测试用例冗长复杂独立测试每个职责
团队协作多人修改易冲突职责边界清晰解耦

精髓​:不要过度设计,但要敏锐识别职责扩散点。当类变得庞大或经常修改时,就是 SRP 的重构时机。

参考:

  1. 设计模式六大原则-CSDN博客
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浩瀚之水_csdn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值