C++|设计模式(〇)|设计模式的六大原则

这里文章只做简要描述,作为扫盲

在软件开发过程中,遵循一定的设计原则可以帮助开发者创建更加灵活、可维护和可扩展的系统。设计模式的六大原则是面向对象设计的核心理念,本文将详细介绍这些原则,并结合实例说明它们的重要性和应用方法。
SOLID原则,分别为单一职责、开放封闭、里氏替换、接口隔离、依赖倒置、合成复用

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

定义:一个类应该只有一个引起变化的原因。即,一个类只负责一个职责。
意义:遵循单一职责原则,可以提高代码的可读性和可维护性,减少代码的复杂度。

class ReportGenerator {
public:
    void generateReport() {
        // 生成报告
    }
};

class ReportPrinter {
public:
    void printReport() {
        // 打印报告
    }
};

在这个示例中,ReportGenerator 负责生成报告,ReportPrinter 负责打印报告,遵循了单一职责原则。

⭐️二、开放封闭原则(OCP, Open/Closed Principle)

定义:软件实体应该对外扩展开放,对修改封闭

意义:通过扩展而不是修改现有代码来实现新的功能,可以提高系统的稳定性和可扩展性。

class Shape {
public:
    virtual void draw() = 0;
};

class Circle : public Shape {
public:
    void draw() override {
        // 画圆
    }
};

class Rectangle : public Shape {
public:
    void draw() override {
        // 画矩形
    }
};

在这个示例中,通过继承 Shape 类来扩展新的形状类,而不需要修改现有的 Shape 类。

三、里氏替换原则(LSP,LisKov Substitution Principle)

定义:子类应该能够替换其基类,并且功能不受影响。

意义:确保继承关系中的子类可以替代基类,保证系统的正确性。

class Bird {
public:
    virtual void fly() {
        // 飞行逻辑
    }
};

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

在这个示例中,Sparrow 可以替代 Bird,且系统功能不受影响。

四、接口隔离原则(ISP, Interface Segregation Principle)

定义:使用多个专门的接口,而不是单一的总接口

意义:减少类之间的依赖,使系统更加灵活和易于维护。

class Printer {
public:
    virtual void print() = 0;
};

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

class AllInOnePrinter : public Printer, public Scanner {
public:
    void print() override {
        // 打印逻辑
    }

    void scan() override {
        // 扫描逻辑
    }
};

在这个示例中,Printer 和 Scanner 接口分离,避免了单一接口的臃肿。

⭐️五、依赖倒置原则(DIP,Dependency Inversion Principle)

定义:高层模块不应该依赖低层模块,二者都应该依赖抽象;抽象不应依赖细节,细节应该依赖抽象。(主要的是我们要依赖抽象层,通过抽象层来解耦高层和底层模块)

意义:通过依赖抽象层来解耦高层和低层模块,提高系统的灵活性和可维护性。

案例:
设想我们有一个开发邮件发送系统的需求。系统有不同的通知方式(如邮件、短信、推送通知等),最初的设计可能会让邮件发送服务直接依赖具体的邮件发送实现(例如 EmailSender 类)。然而,这样会使得系统扩展困难,维护成本高,因为每次增加新的通知方式(例如短信)时,代码都需要修改。

class Database {
public:
    virtual void connect() = 0;
};

class MySQLDatabase : public Database {
public:
    void connect() override {
        // MySQL 连接逻辑
    }
};

class Application {
private:
    Database& db;
public:
    Application(Database& db) : db(db) {}
    
    void run() {
        db.connect();
        // 业务逻辑
    }
};

在这个示例中,Application 依赖于 Database 抽象接口,而不是具体实现(MySQL数据库,因为我们可能连接 Redis 等别的数据库),这就叫高层模块不依赖于低层模块,遵循了依赖倒置原则。

⭐️六、迪米特法则(LoD,Law of Demeter)

它的核心思想是一个对象应该尽可能少地了解其他对象的内部细节,从而降低系统的耦合性,提高代码的模块化、可维护性和可扩展性。

首先我会距一个违反迪米特法则的代码:

class Engine {
public:
    void start() {
        cout << "Engine started." << endl;
    }
};

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

class Person {
public:
    void startCar(Car& car) {
        car.getEngine()->start();  // 违背迪米特法则
    }
};

在这个例子中,Person 类通过 Car 调用了 Engine 的方法,这违背了迪米特法则。Person 对象不应该知道 Car 的 Engine,更不应该直接操作 Engine。

改进如下:

class Engine {
public:
    void start() {
        cout << "Engine started." << endl;
    }
};

class Car {
public:
    void startEngine() {  // Car 内部负责操作 Engine
        engine.start();
    }
private:
    Engine engine;
};

class Person {
public:
    void startCar(Car& car) {
        car.startEngine();  // 遵守迪米特法则
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值