Skills101

OOP Concepts · Lesson 6 of 8 · Updated ·

SOLID Principles — Five Rules for Clean Object-Oriented Code

SOLID is a set of five design rules that keep object-oriented code easy to change and test. They're asked in interviews for experienced roles and increasingly for freshers too.

SOLID: S — single responsibility; O — open/closed; L — Liskov substitution; I — interface segregation; D — dependency inversion

S — Single Responsibility Principle

A class should have one reason to change.

❌ One Invoice class that calculates totals, saves to the database and sends emails. A change to email wording forces you to touch billing code.

✅ Split it:

class Invoice:
    def __init__(self, items): self.items = items
    def total(self): return sum(price * qty for price, qty in self.items)

class InvoiceRepository:
    def save(self, invoice): return f"saved invoice of {invoice.total()}"

class InvoiceMailer:
    def send(self, invoice, to): return f"mailed {invoice.total()} to {to}"

inv = Invoice([(499, 2), (99, 1)])
print(inv.total(), "|", InvoiceRepository().save(inv), "|", InvoiceMailer().send(inv, "asha@x.in"))
1097 | saved invoice of 1097 | mailed 1097 to asha@x.in

O — Open/Closed Principle

Classes should be open for extension, closed for modification.

❌ Every new discount type means editing an if … elif … chain inside apply_discount().

✅ Add a new class instead:

class Discount:
    def apply(self, price): return price

class Festive(Discount):
    def apply(self, price): return price * 0.8

class Student(Discount):
    def apply(self, price): return price - 200

def checkout(price, discount: Discount):
    return discount.apply(price)

print(checkout(2000, Festive()), checkout(2000, Student()), checkout(2000, Discount()))
1600.0 1800 2000

A new Diwali discount is a new class — checkout never changes.

L — Liskov Substitution Principle

A child class must work anywhere its parent works, without surprises.

Classic violation: Square extends Rectangle. Code that sets width = 5 and height = 4 expects area 20, but a Square forces both sides equal and breaks it. If a subclass needs to refuse or change the meaning of a parent method, it shouldn't be a subclass.

Signs of violation: a subclass throws "not supported" for an inherited method, or callers need if isinstance(x, Child) checks.

I — Interface Segregation Principle

Many small, focused interfaces are better than one big one.

❌ An interface Machine with print(), scan(), fax() forces a simple printer to implement scan() and fax() with errors.

✅ Separate Printer, Scanner, Fax interfaces; an all-in-one implements all three, a basic printer implements one.

D — Dependency Inversion Principle

Depend on abstractions, not concrete classes.

❌ OrderService creates MySQLDatabase() inside itself → you can't test it without a real database or switch to PostgreSQL easily.

✅ Pass the dependency in (dependency injection):

class Store:                        # abstraction
    def save(self, order): raise NotImplementedError

class MySQLStore(Store):
    def save(self, order): return f"MySQL: saved {order}"

class FakeStore(Store):             # for tests — no database needed
    def save(self, order): return f"test: pretended to save {order}"

class OrderService:
    def __init__(self, store: Store):   # injected
        self.store = store
    def place(self, order):
        return self.store.save(order)

print(OrderService(MySQLStore()).place("order#42"))
print(OrderService(FakeStore()).place("order#42"))
MySQL: saved order#42
test: pretended to save order#42

Frameworks like Spring (Java) do this injection for you.

Common mistakes

  • Applying SOLID mechanically to tiny scripts — it's for code that keeps growing.
  • Confusing Dependency Inversion (principle) with Dependency Injection (a technique to achieve it).

Quick recap

  • S one reason to change · O extend, don't edit · L subclasses must be substitutable · I small interfaces · D depend on abstractions.
  • Goal: change one thing without breaking others, and test easily.

Practice what you learned

📝 Quiz: SOLID Principles5 questions · instant answers & explanations · +10 XP · counts towards your free certificateTake the quiz →