系列文章目录

【C++设计模式】总纲



前言

在软件开发中,设计原则是指导我们编写高质量代码的重要准则。
为了写出符合高内聚、低耦合原则的代码,我们需要遵循一些公认的设计原则。
以下是C++中常见的八大设计原则的简单介绍,以及符合和违背这些原则的代码示例。

C++ 八大设计原则

1. 单一职责原则 (Single Responsibility Principle, SRP)

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

即一个类只负责一个职责。可以提高类的可读性和可维护性,降低类的复杂度,但可能导致类的数量增加,进而增加系统设计的复杂性。

  • 违背原则的代码示例:
class Order {
public:
    void addItem(const std::string& item) {
        // 添加商品
    }

    void log(const std::string& message) {  //错误:实现了不该由该类实现的功能
        // 记录日志
    }
};
  • 符合原则的代码示例:
class Logger {
public:
    void log(const std::string& message) {
        // 记录日志
    }
};
class Order {
    void addItem(const std::string& item) {
        // 添加商品
    }
};

2. 开放封闭原则 (Open/Closed Principle, OCP)

原则:软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。

可以提高系统的可扩展性,减少修改代码引入错误的风险,但需要仔细设计抽象层次,可能增加系统的复杂度。

  • 违背原则的代码示例:
class Shape {
public:
    enum Type { Circle, Rectangle } type;
    double radius, width, height;   //错误:类外可修改类内成员变量

    double area() const {
        switch (type) {  //错误:失去扩展性,想修改必须修改类本体
            case Circle:
                return 3.14 * radius * radius;
            case Rectangle:
                return width * height;
        }
        return 0;
    }
};
  • 符合原则的代码示例:
class Shape {
public:
    virtual double area() const = 0;
};

class Circle : public Shape {
public:
    double area() const override {
        return 3.14 * radius * radius;
    }
private:
    double radius;
};

class Rectangle : public Shape {
public:
    double area() const override {
        return width * height;
    }
private:
    double width, height;
};

3. 里氏替换原则 (Liskov Substitution Principle, LSP)

原则:子类对象应该能够替换掉基类对象而不影响程序的正确性。

  • 违背原则的代码示例:
class Bird {
public:
    virtual void fly() {
        // 飞行
    }
};

class Ostrich : public Bird {  //鸵鸟不能飞行
public:
    void fly() override {
        throw std::logic_error("Ostrich can't fly");
    }
};
  • 符合原则的代码示例:
class Bird {
public:
    virtual void fly() {
        // 飞行
    }
};

class Sparrow : public Bird {  //麻雀可以飞行
public:
    void fly() override {
        // 麻雀飞行
    }
};

4. 接口隔离原则 (Interface Segregation Principle, ISP)

原则:不应该强迫客户端依赖它们不需要的接口,接口应小而完备。

即类间的依赖关系应该建立在最小的接口上。可以减少代码的冗余,提高系统的灵活性和可维护性,但可能导致接口数量增加,进而增加系统设计的复杂性。

  • 违背原则的代码示例:
class IMachine {
public:
    virtual void print() = 0;
    virtual void scan() = 0;
};

class Printer : public IMachine {
public:
    void print() override {
        // 打印
    }

    void scan() override {
        // 错误:不需要实现
    }
};
  • 符合原则的代码示例:
class IPrinter {
public:
    virtual void print() = 0;
};

class IScanner {
public:
    virtual void scan() = 0;
};

class Printer : public IPrinter {
public:
    void print() override {
        // 打印
    }
};

class Scanner : public IScanner {
public:
    void scan() override {
        // 扫描
    }
};

5. 依赖倒置原则 (Dependency Inversion Principle, DIP)

原则:高层模块不应该依赖低层模块。

二者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。

  • 违背原则的代码示例:
class WiredKeyboard {
public:
    void type() {
        // 有线键盘打字
    }
};

class Computer {
public:
    void input() {
        keyboard_.type();
    }

private:
    WiredKeyboard keyboard_;
};
  • 符合原则的代码示例:
class IKeyboard {
public:
    virtual void type() = 0;
};

class WiredKeyboard : public IKeyboard {
public:
    void type() override {
        // 有线键盘打字
    }
};

class Computer {
public:
    Computer(IKeyboard* keyboard) : keyboard_(keyboard) {}

    void input() {
        keyboard_->type();
    }

private:
    IKeyboard* keyboard_;
};

6. 迪米特法则 (Law of Demeter, LoD)

原则:一个对象应该对其他对象有最少的了解。

  • 违背原则的代码示例:
class Engine {
public:
    void start() {
        // 启动引擎
    }
};

class Car {
public:
    Engine& getEngine() {
        return engine;
    }

private:
    Engine engine;
};

class Driver {
public:
    void startCar(Car& car) {
        car.getEngine().start();
    }
};
  • 符合原则的代码示例:
class Engine {
public:
    void start() {
        // 启动引擎
    }
};

class Car {
public:
    void start() {
        engine.start();
    }

private:
    Engine engine;
};

7. 合成复用原则 (Composite Reuse Principle, CRP)

原则:尽量使用对象组合,而不是继承来达到复用的目的。

继承耦合度高,一定程度上破坏了封装性。

  • 违背原则的代码示例:
class Engine {
public:
    void start() {
        // 启动引擎
    }
};

class Car : public Engine {
public:
    void start() {
        Engine::start();
    }
};
  • 符合原则的代码示例:
class Engine {
public:
    void start() {
        // 启动引擎
    }
};

class Car {
public:
    Car(Engine* engine) : engine_(engine) {}

    void start() {
        engine_->start();
    }

private:
    Engine* engine_;
};

8. 最少知识原则 (Principle of Least Knowledge, PLK)

原则:一个软件实体应当尽可能少地与其他实体发生相互作用。

  • 违背原则的代码示例:
class Wheel {
public:
    void rotate() {
        // 轮子旋转
    }
};

class Car {
public:
    Wheel& getWheel() {
        return wheel;
    }

private:
    Wheel wheel;
};

class Driver {
public:
    void drive(Car& car) {
        car.getWheel().rotate();
    }
};
  • 符合原则的代码示例:
class Wheel {
public:
    void rotate() {
        // 轮子旋转
    }
};

class Car {
public:
    void move() {
        wheel.rotate();
    }

private:
    Wheel wheel;
};
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐