Lesson 11 � Advanced
LLD: SOLID & Design Patterns
Low Level Design mein tum classes, interfaces, aur relationships design karte ho. SOLID principles aur design patterns � clean code ki foundation hain.
SOLID Principles
# S - Single Responsibility Principle
✓ Har class ka ek hi responsibility hona chahiye
✓ Bad: User class jo data bhi store karti hai aur email bhi bhejti hai
✓ Good: User class (data) + EmailService (email)
# O - Open/Closed Principle
✓ Open for extension, closed for modification
✓ Bad: Har naye payment type ke liye Payment class modify karo
✓ Good: Payment interface + CreditCardPayment, UPIPayment, etc.
# L - Liskov Substitution Principle
✓ Derived classes base class ko replace kar sakein
✓ Bad: Square class inherits Rectangle but width/height alag behave kare
✓ Good: Dono alag se implement karo
# I - Interface Segregation Principle
✓ Chhote-chhote specific interfaces banao, ek bada interface nahi
✓ Bad: Animal interface � fly(), swim(), walk() (sab animals nahi kar paate)
✓ Good: Flyable, Swimmable, Walkable interfaces
# D - Dependency Inversion Principle
✓ High-level modules low-level modules pe depend nahi karte
✓ Dono abstractions pe depend karte hain
✓ Bad: OrderService directly MySQL database use kare
✓ Good: OrderService depends on Database interface (abstraction)
Mnemonic: SOLID yaad rakho � Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion. Har principle ek specific problem solve karta hai code maintainability mein.
Creational Design Patterns
# 1. Singleton Pattern
✓ Ek hi instance of class exist kare
✓ Database connection, Logger
class Database:
_instance = None
@staticmethod
def get_instance():
if Database._instance is None:
Database._instance = Database()
return Database._instance
# 2. Factory Pattern
✓ Object creation logic encapsulate karo
✓ Client ko pata nahi kaunsi class instantiate ho rahi
class PaymentFactory:
@staticmethod
def create_payment(method):
if method == "credit_card":
return CreditCardPayment()
elif method == "upi":
return UPIPayment()
# 3. Builder Pattern
✓ Complex objects step-by-step build karo
✓ Telescoping constructor se bacho
query = (QueryBuilder()
.select("name", "email")
.from_table("users")
.where("age > 18")
.order_by("name")
.build())
Structural Design Patterns
# 1. Adapter Pattern
✓ Incompatible interfaces ko compatible banao
✓ Legacy system integrate karna ho
class OldPaymentSystem:
def make_payment_legacy(self, amt):
return f"Paid {amt}"
class PaymentAdapter:
def __init__(self, old_system):
self.old_system = old_system
def pay(self, amount):
return self.old_system.make_payment_legacy(amount)
# 2. Decorator Pattern
✓ Behavior dynamically add/remove karo
✓ Inheritance se
class Coffee:
def cost(self): return 50
class MilkDecorator:
def __init__(self, coffee):
self.coffee = coffee
def cost(self):
return self.coffee.cost() + 20
# Usage: MilkDecorator(Coffee()) ✓ cost = 70
# 3. Proxy Pattern
✓ Real object ki jagah proxy use karo
✓ Caching, lazy loading, access control
class RealImage:
def display(self):
print("Displaying image")
class ProxyImage:
def __init__(self, filename):
self.filename = filename
self.real_image = None
def display(self):
if self.real_image is None:
self.real_image = RealImage() # lazy load
self.real_image.display()
Behavioral Design Patterns
# 1. Observer Pattern
✓ Ek change ho toh saare dependents ko notify karo
✓ Event-driven systems
class EventEmitter:
def __init__(self):
self.listeners = {}
def on(self, event, callback):
self.listeners.setdefault(event, []).append(callback)
def emit(self, event, data):
for cb in self.listeners.get(event, []):
cb(data)
# 2. Strategy Pattern
✓ Algorithm ka behavior runtime pe change karo
✓ Multiple strategies, client choose kare
class SortStrategy:
def sort(self, data): pass
class QuickSort(SortStrategy):
def sort(self, data): return quicksort(data)
class MergeSort(SortStrategy):
def sort(self, data): return mergesort(data)
class Sorter:
def __init__(self, strategy):
self.strategy = strategy
def sort(self, data):
return self.strategy.sort(data)
# 3. State Pattern
✓ Object ka behavior uske state ke hisaab se change
✓ Finite state machines
class OrderState:
def next(self, order): pass
def status(self): pass
class NewOrder(OrderState):
def next(self, order):
order.state = ProcessingOrder()
def status(self): return "New"
class ProcessingOrder(OrderState):
def next(self, order):
order.state = ShippedOrder()
def status(self): return "Processing"
Exercise
Question: SOLID mein S kya represent karta hai? (3 words)
Question: Object creation logic ko encapsulate karne wala pattern konsa hai jo client ko concrete class nahi batata? (1 word)
Common mistakes
- Over-engineering: Har cheez mein design pattern mat lagao. Simple solution pehle, pattern tab jab zaroorat ho.
- SOLID galat apply: Single Responsibility ka matlab nahi ki har method ek class mein ho. Reasonable boundaries rakho.
- Singleton overuse: Global state create karta hai, testing mushkil. Dependency injection prefer karo.
- Pattern without problem: Pehle problem samjho, phir pattern choose karo. Pattern for pattern's sake galat hai.
Lesson complete?
LLD basics samajh aa gayi✓ Ab Machine Coding Round seekhte hain � interview mein kaise clean code likhte hain.