引言:C++语境下的SOLID
SOLID 是罗伯特·马丁提出的五个面向对象设计基本原则的首字母缩写。对于C++这种具有强大静态类型、多重继承和RAII的语言来说,这些原则具有特殊的意义。在高级水平上,理解SOLID原则能够创建灵活、可测试和可扩展的系统,避免诸如“上帝类”或紧耦合等反模式。
在本文中,我们将通过实际的C++ (17/20) 代码示例来剖析每个原则,重点关注实现细节:使用 std::unique_ptr、std::function、CRTP、虚析构函数和现代惯用法。
1. 单一职责原则 (SRP)
定义: 一个类应该只有一个引起它变化的原因。
在实践中,这意味着一个类只负责一个业务实体或一个操作。违反SRP会导致职责“耦合”,使测试和修改变得复杂。
违反示例
class Report {public: void generate() { /* 生成数据 */ } void saveToFile(const std::string& path) { /* 写入文件 */ } void sendEmail(const std::string& to) { /* 发送邮件 */ }};这里 Report 同时负责生成、保存和发送——有三个引起变化的原因。
遵循SRP的重构
class Report {public: void generate() { /* 生成数据 */ }};
class ReportSaver {public: void save(const Report& report, const std::string& path);};
class EmailSender {public: void send(const Report& report, const std::string& to);};现在每个类都有单一的职责。这简化了单元测试和代码复用。
2. 开闭原则 (OCP)
定义: 软件实体应该对扩展开放,对修改关闭。
在C++中,这通常通过多态(虚函数)或模板(CRTP)来实现。对于高级水平,我们将探讨这两种技术。
多态方法(虚函数)
class Shape {public: virtual double area() const = 0; virtual ~Shape() = default;};
class Circle : public Shape { double r;public: Circle(double r) : r(r) {} double area() const override { return 3.14 * r * r; }};
class Rectangle : public Shape { double w, h;public: Rectangle(double w, double h) : w(w), h(h) {} double area() const override { return w * h; }};添加新图形(例如 Triangle)不需要修改现有类——只需创建一个新的子类。
模板方法(CRTP——奇异递归模板模式)
template<typename Derived>class ShapeBase {public: double area() const { return static_cast<const Derived*>(this)->area_impl(); }};
class Circle : public ShapeBase<Circle> { double r;public: Circle(double r) : r(r) {} double area_impl() const { return 3.14 * r * r; }};CRTP 提供了静态多态,没有虚函数调用的开销,这对于高性能C++至关重要。
3. 里氏替换原则 (LSP)
定义: 基类对象应该可以被派生类对象替换,而不会影响程序的正确性。
C++中经典的LSP违反案例是重写虚方法时削弱前置条件或加强后置条件。我们来看一个“矩形-正方形”层次结构的例子。