OOP Fundamentals
Class Relationships
Design Principles
- DRY Principle
- YAGNI Principle
- KISS Principle
- SOLID Principles with Pictures
- SOLID Principles with Code
Example
What design principle(s) below class is breaking? this is adopted from https://x.com/SumitM_X
class FeeCalculator {
public:
double calculateFee(Instrument* instrument) {
if (dynamic_cast<Stock*>(instrument)) {
return 1.5;
} else if (dynamic_cast<Bond*>(instrument)) {
return 2.0;
} else {
return 0.0;
}
}
};
1. Violation of the Open–Closed Principle (OCP)
OCP: Classes should be open for extension, but closed for modification.
Your calculateFee() method must be edited every time you add a new instrument type:
else if (dynamic_cast<Option*>(instrument)) ...
This means your class is not closed for modification. A single new instrument forces changes in this class.
2. Violation of the Single Responsibility Principle (SRP)
SRP: A class should have only one reason to change.
- Knowing about all instrument types
- Deciding how to compute fee for each instrument
This mixes instrument type logic with fee logic → one class handling multiple responsibilities.
3. Violation of Polymorphism / Liskov Substitution Principle (LSP)
Instead of using dynamic dispatch, the class:
- Checks object types explicitly using
dynamic_cast - Branches based on concrete types
This breaks proper polymorphism because:
- The base class
Instrumentcannot be substituted for its subclasses without special handling. - Each subclass should define its own fee behavior, not the calculator guessing.
4. Violation of the Dependency Inversion Principle (DIP)
DIP: Depend on abstractions, not concrete types.
This class depends directly on the concrete classes:
Stock
Bond
Making it rigid and fragile.
Correct OOP version (polymorphism)
class Instrument {
public:
virtual ~Instrument() = default;
virtual double fee() const = 0;
};
class Stock : public Instrument {
public:
double fee() const override { return 1.5; }
};
class Bond : public Instrument {
public:
double fee() const override { return 2.0; }
};
class FeeCalculator {
public:
double calculateFee(const Instrument* instrument) const {
return instrument->fee(); // polymorphic call
}
};