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)
原则含义:
客户端不应被迫依赖它不需要的接口。一个“胖”接口应拆分为多个更小、更具体的接口,使得每个客户端只依赖于自己感兴趣的方法。
举例说明:
假设有一个多功能设备接口包含打印、扫描和传真方法,但某些客户端只需要打印功能。可以将接口拆分为 IPrinter
、IScanner
、IFax
等。
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 通过依赖抽象降低高层与低层模块之间的耦合性。
这些原则是面向对象设计中的核心思想,能够帮助我们构建出易于维护、扩展和复用的软件系统。
参考资料:
citeturn0search0、citeturn0search9
以上就是 OO 设计原则的详细介绍及 C++ 实例,希望对你理解和应用面向对象设计有所帮助。