SOLID is five famous principles that keep object-oriented code easy to read and change. Each letter is one rule. You don't need them on day one — but knowing them makes you a stronger designer.
Letter
Principle
Plain English
S
Single Responsibility
One class, one job.
O
Open/Closed
Add features without editing old code.
L
Liskov Substitution
A subclass should work anywhere its parent does.
I
Interface Segregation
Many small interfaces beat one giant one.
D
Dependency Inversion
Depend on ideas, not exact details.
1️⃣ S — Single Responsibility
A class should have one reason to change. Don't mix saving files with calculating math.
# 😵 Does too much
class Report:
def calculate(self): ...
def save_to_file(self): ... # different job!
# 😀 Split responsibilities
class Report:
def calculate(self): ...
class ReportSaver:
def save(self, report): ...
2️⃣ O — Open/Closed
Code should be open to extension, closed to modification. Add new shapes without rewriting the old ones.
class Shape:
def area(self):
raise NotImplementedError
class Circle(Shape):
def __init__(self, r): self.r = r
def area(self): return 3.14 * self.r * self.r
class Square(Shape):
def __init__(self, s): self.s = s
def area(self): return self.s * self.s
💡 The win
To add a Triangle, you write a new class — you never touch Circle or Square. Less risk of breaking working code!
3️⃣ L, I, D in one breath
Liskov: if Penguin is a Bird, it shouldn't break code that calls bird.fly() — so maybe not every bird should have fly().
Interface Segregation: don't force a class to implement methods it doesn't use.
Dependency Inversion: a NotificationService should depend on a general "sender," not specifically on "EmailSender" — so you can swap in SMS later.
✅ What you learned
Single Responsibility — one class, one job.
Open/Closed — extend without editing.
Liskov — subclasses must behave like their parent.
Interface Segregation — keep interfaces small.
Dependency Inversion — depend on abstractions.
🎮 Time to Practice!
Refactor toward SOLID design. 🧱
1️⃣
Task 1: Split Responsibilities
Medium
Keep Report only for calculating, and put saving in a separate ReportSaver. Finish both methods so the output is 42 then Saved: 42.
class ReportSaver:
def save(self, value):
return "Saved: " + str(value)
2️⃣
Task 2: Open/Closed Shapes
Challenge
Add a Square class that extends Shape without changing Circle. Circle(5).area() → 78.5, Square(4).area() → 16.
class Square(Shape):
def __init__(self, s):
self.s = s
def area(self):
return self.s * self.s
print(Circle(5).area())
print(Square(4).area())
🔌
Task 3: Dependency Inversion
Boss
The Notifier takes any sender object with a send method — so we can swap Email for SMS without changing Notifier. Finish both senders' send methods.
class SmsSender:
def send(self, msg):
return "Sending via SMS: " + msg