Open/Closed priciple (OCP)
- Classes/modules should open for extension but closed for modification.
- This means you should add new functionality without changing the existing code.
- Benifits - Increased Stability, reduced risk of introducing bugs when adding new features, and improved reusability.
- Here is an example - Create different types of shapes
/**
* Bad example
**/
// If you want to add a new shape (e.g. Triagle), you'd have to modify the ShapeDrawer class
// by adding another if/else block. This violates OCP because you're modifying existing code
// to add new functionallity.
#include <iostream>
#include <vector>
enum clas ShapeType { Circle, Square };
class Shape {
public:
Shape(ShapeType type) : type_(type) {}
Shape getType() const { return type_;}
virtual void draw() = 0;
virtual ~Shape() = default;
protected:
ShapeType type_;
};
class Circle : public Shape {
public:
Circle() : Shape(ShapeType::Circle) {}
void draw() override { std::cout << "Drawing a circle\n"; }
};
class Square : public Shape {
public:
Square() : Shape(ShapeType::Square) {}
void draw() override { std::cout << "Drawing a square\n"; }
};
class ShapeDrawer {
public:
void drawShapes(const std::vector<Shape*>& shapes) {
for (const Shape* s : shapes) {
if (s->getType() == ShapeType::Circle) {
static_cast<const Circle*>(s)->draw();
} else if (s->getType() == ShapeType::Square) {
static_cast<const Square*>(s)->draw();
} // Add more if/else blocks for new shapes - Violates OCP
}
}
};
int main() {
std::vector<Shape*> shapes = {new Circle(), new Square()};
ShapeDrawer drawer;
drawer.drawShapes(shapes);
for (auto shape: shapes) {
delete shape;
}
shapes.clear();
return 0;
}