当前位置: 首页 > news >正文

OO设计原则的cpp举例

下面我们详细介绍常见的面向对象设计原则,并用 C++ 举例说明如何在代码中体现这些原则。


1. 单一职责原则(SRP)

原则含义:
一个类应该只有一个引起它变化的原因,也就是说一个类只负责一项职责。这样可以降低类的复杂度,提高内聚性,方便维护和复用。

举例说明:
假设在一个学生管理系统中,我们可能会将学生的业务操作(增删改查)和数据存储操作混合在同一个类中,这样类的职责不单一。遵循 SRP 后,我们可以拆分成两个类:一个专注于学生业务操作,一个专注于数据的读写。

C++ 示例:

// 负责学生的业务操作
class StudentManager {
public:
    void addStudent(const std::string& name) {
        // 添加学生的业务逻辑
    }
    void removeStudent(const std::string& name) {
        // 删除学生的业务逻辑
    }
    // …其他学生操作
};

// 负责学生数据的存取
class StudentRepository {
public:
    void save(const std::vector<std::string>& students) {
        // 将学生数据保存到文件或数据库中
    }
    std::vector<std::string> load() {
        // 从文件或数据库中加载学生数据
        return {};
    }
};

2. 开放-封闭原则(OCP)

原则含义:
软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。也就是说,当需求变化时,我们应该通过扩展代码而不是修改已有代码来实现新功能。

举例说明:
以图形绘制为例,我们设计一个基类 Shape,提供一个虚函数 draw()。新增图形时,只需继承 Shape 并实现自己的 draw() 方法,而无需修改绘图函数。

C++ 示例:

// 抽象基类:图形
class Shape {
public:
    virtual void draw() const = 0;
    virtual ~Shape() {}
};

// 圆形实现
class Circle : public Shape {
public:
    void draw() const override {
        // 绘制圆形的具体逻辑
        std::cout << "Drawing Circle" << std::endl;
    }
};

// 矩形实现
class Rectangle : public Shape {
public:
    void draw() const override {
        // 绘制矩形的具体逻辑
        std::cout << "Drawing Rectangle" << std::endl;
    }
};

// 绘图函数,只依赖于抽象接口
void renderShape(const Shape& shape) {
    shape.draw();
}

int main() {
    Circle circle;
    Rectangle rectangle;
    renderShape(circle);
    renderShape(rectangle);
    return 0;
}

3. 里氏替换原则(LSP)

原则含义:
子类对象必须能够替换基类对象而不会破坏程序的正确性,即任何使用基类的地方,都可以用子类来代替,而程序行为不变。

常见问题:
经典例子是正方形与长方形的问题。如果将正方形直接继承自长方形,由于正方形要求长宽相等,可能导致在设置长和宽时产生不一致,从而违反 LSP。

C++ 示例:

// 基类:长方形
class Rectangle {
protected:
    double width;
    double height;
public:
    virtual void setWidth(double w) { width = w; }
    virtual void setHeight(double h) { height = h; }
    virtual double area() const { return width * height; }
    virtual ~Rectangle() {}
};

// 正方形不宜简单地继承自 Rectangle
// 因为 setWidth 与 setHeight 可能导致状态不一致
class Square : public Rectangle {
public:
    // 重写设置方法,保证宽高始终相等
    void setWidth(double w) override {
        width = height = w;
    }
    void setHeight(double h) override {
        width = height = h;
    }
    // area() 方法可以直接继承,但注意:在设计时应考虑是否真的适合用继承来描述正方形与长方形的关系
};

void processRectangle(Rectangle& rect) {
    rect.setWidth(5);
    rect.setHeight(4);
    // 对于 Rectangle,面积应为20
    std::cout << "Area: " << rect.area() << std::endl;
}

int main() {
    Rectangle r;
    r.setWidth(5);
    r.setHeight(4);
    processRectangle(r); // 输出 20

    Square s;
    // 如果用 Square 替换 Rectangle,调用过程会修改为正方形的行为
    processRectangle(s); // 输出可能不是 20,而是 16,违反 LSP
    return 0;
}

说明: 正方形与长方形之间的继承关系容易引起混淆,设计时可以考虑采用组合而不是继承来避免问题。


4. 接口隔离原则(ISP)

原则含义:
客户端不应被迫依赖它不需要的接口。一个“胖”接口应拆分为多个更小、更具体的接口,使得每个客户端只依赖于自己感兴趣的方法。

举例说明:
假设有一个多功能设备接口包含打印、扫描和传真方法,但某些客户端只需要打印功能。可以将接口拆分为 IPrinterIScannerIFax 等。

C++ 示例:

// 分离接口
class IPrinter {
public:
    virtual void print(const std::string& document) = 0;
    virtual ~IPrinter() {}
};

class IScanner {
public:
    virtual void scan(const std::string& document) = 0;
    virtual ~IScanner() {}
};

class IFax {
public:
    virtual void fax(const std::string& document) = 0;
    virtual ~IFax() {}
};

// 具体设备实现了打印和扫描,不支持传真
class MultiFunctionPrinter : public IPrinter, public IScanner {
public:
    void print(const std::string& document) override {
        std::cout << "Printing: " << document << std::endl;
    }
    void scan(const std::string& document) override {
        std::cout << "Scanning: " << document << std::endl;
    }
};

void clientPrint(IPrinter* printer) {
    printer->print("Test Document");
}

int main() {
    MultiFunctionPrinter mfp;
    clientPrint(&mfp);
    return 0;
}

5. 依赖倒置原则(DIP)

原则含义:
高层模块不应依赖于低层模块,二者都应依赖于抽象;抽象不应依赖于细节,细节应依赖于抽象。这使得系统更容易扩展和维护。

举例说明:
例如在支付系统中,高层模块(订单)只依赖于支付接口,而具体的支付方式(支付宝、微信支付等)则实现该接口,高层模块无需修改就可以支持更多支付方式。

C++ 示例:

// 抽象接口
class Payment {
public:
    virtual void pay(double amount) = 0;
    virtual ~Payment() {}
};

// 具体支付方式:支付宝
class Alipay : public Payment {
public:
    void pay(double amount) override {
        std::cout << "Paying " << amount << " using Alipay." << std::endl;
    }
};

// 具体支付方式:微信支付
class WechatPay : public Payment {
public:
    void pay(double amount) override {
        std::cout << "Paying " << amount << " using WechatPay." << std::endl;
    }
};

// 高层模块:订单
class Order {
private:
    Payment* paymentMethod;
public:
    // 通过依赖注入设置支付方式
    void setPaymentMethod(Payment* method) {
        paymentMethod = method;
    }
    void processOrder(double amount) {
        if(paymentMethod)
            paymentMethod->pay(amount);
    }
};

int main() {
    Order order;
    Alipay alipay;
    order.setPaymentMethod(&alipay);
    order.processOrder(100.0);

    WechatPay wechat;
    order.setPaymentMethod(&wechat);
    order.processOrder(200.0);
    return 0;
}

小结

这五大原则(即 SOLID 原则)分别强调:

  • SRP 保证类职责单一;
  • OCP 让系统能够在不修改已有代码的情况下扩展新功能;
  • LSP 保证子类能够替换父类;
  • ISP 让接口足够细化,只暴露客户端所需的方法;
  • DIP 通过依赖抽象降低高层与低层模块之间的耦合性。

这些原则是面向对象设计中的核心思想,能够帮助我们构建出易于维护、扩展和复用的软件系统。


参考资料:
citeturn0search0、citeturn0search9

以上就是 OO 设计原则的详细介绍及 C++ 实例,希望对你理解和应用面向对象设计有所帮助。

相关文章:

  • centos 7 安装python3 及pycharm远程连接方法
  • 【信息系统项目管理师-案例真题】2009上半年案例分析答案和详解
  • 心理咨询小程序的未来发展
  • Java 面试合集(2024版)
  • 力扣3102.最小化曼哈顿距离
  • linux--多进程基础(2)GDB多进程调试(面试会问)
  • 大数据开发平台的框架
  • 一个不错的API测试框架——Karate
  • 【2025深度学习环境搭建-2】pytorch+Docker+VS Code+DevContainer搭建本地深度学习环境
  • JavaAPI(lambda表达式、流式编程)
  • echarts图表初始化搭建
  • 【数据结构进阶】哈希表
  • OpenSSL 生成非对称密钥对
  • 嵌入式科普(33)深度解析C语言中的const和volatile关键字
  • 浏览器跨域问题的原因分析及常见解决方案
  • flutter Column嵌套ListView高度自适应问题
  • stm32-电源控制
  • 第N1周:one-hot编码案例
  • Mysql 主从集群同步延迟问题怎么解决
  • 启动Redis报错记录
  • 欧莱雅的网络营销策划方案/seo 资料包怎么获得
  • 池州做网站/百度移动应用
  • 专业做网文的网站/b站在线观看人数在哪
  • 搭建个人视频网站/网站建设策划书范文
  • 自己做网站需要学些什么/网站运营seo实训总结
  • 做网站是先买域名还是/杭州seo搜索引擎优化公司