How do you implement OCP through composition?
OCP through composition is implemented so that a class is not overridden through inheritance, but instead receives an object that defines the behavior. New behavior is added by creating new strategies/components, not by changing existing code.
In detail:
1. A class gets its dependency through an interface or abstraction
Instead of overriding methods in descendants, the class accepts an object that implements a defined contract. This object defines the variable behavior.
2. The code is closed for modification
The class that uses the dependency does not change. It simply calls the methods of the injected strategy.
3. New behavior is added by creating a new component
To implement a new behavior variant, a new class is created that implements the same interface. Existing classes remain unchanged - that is what following OCP means.
Example (payment strategy):
Behavior interface:
class PaymentStrategy:
def pay(self, amount):
raise NotImplementedErrorImplementations:
class CardPayment(PaymentStrategy):
def pay(self, amount):
print("Card payment:", amount)
class PayPalPayment(PaymentStrategy):
def pay(self, amount):
print("PayPal payment:", amount)The class that uses the strategy:
class CheckoutService:
def __init__(self, payment_strategy: PaymentStrategy):
self.payment_strategy = payment_strategy
def process(self, amount):
self.payment_strategy.pay(amount)Extension:
class CryptoPayment(PaymentStrategy):
def pay(self, amount):
print("Crypto payment:", amount)Why this is OCP
- CheckoutService never changes. It is fully closed for modification.
- New behavior is added through new strategies. CryptoPayment is a new class that does not require changing the existing system.
- Client code simply plugs in a new component. For example:
checkout = CheckoutService(CryptoPayment())
checkout.process(100)- Composition is more flexible than inheritance. Behavior can be swapped at runtime, combined, or changed without creating new class hierarchies.
Summary: OCP through composition is implemented using strategies, delegation, and dependency injection: the base code stays unchanged, and new behavior is added by creating new components that are passed into the class from outside.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.