Problem Statement
When code depends directly on concrete classes, changing implementations requires modifying all dependent code. This tight coupling makes the system fragile and hard to extend or test.
The diagram shows the client depending only on the interface, while multiple implementations can vary independently.
### Before: Program to implementation (tight coupling) class PaymentProcessor: def pay(self, amount): print(f"Processing payment of {amount} using Stripe") class OrderService: def __init__(self): self.processor = PaymentProcessor() def checkout(self, amount): self.processor.pay(amount) order = OrderService() order.checkout(100) ### After: Program to interface (loose coupling) from abc import ABC, abstractmethod class PaymentProcessorInterface(ABC): @abstractmethod def pay(self, amount): pass class StripeProcessor(PaymentProcessorInterface): def pay(self, amount): print(f"Processing payment of {amount} using Stripe") class PaypalProcessor(PaymentProcessorInterface): def pay(self, amount): print(f"Processing payment of {amount} using PayPal") class OrderService: def __init__(self, processor: PaymentProcessorInterface): self.processor = processor def checkout(self, amount): self.processor.pay(amount) stripe = StripeProcessor() order = OrderService(stripe) order.checkout(100) paypal = PaypalProcessor() order2 = OrderService(paypal) order2.checkout(200)