Composition is an OOP design principle where:
👉 A class is built using other classes.
Instead of:
IS-A relationship (Inheritance)
Composition uses:
HAS-A relationship
Example:
Car HAS-A Engine
House HAS-A Room
Computer HAS-A CPU
Composition means:
Objects working together to build behavior
✔ One object contains another
✔ Reuse via collaboration
✔ Flexible & modular design
A class stores another object as an attribute.
class Engine:
def start(self):
print("Engine started")
class Car:
def __init__(self):
self.engine = Engine() # Composition
def start_car(self):
self.engine.start()
c = Car()
c.start_car()Output:
Engine started
✔ Car does NOT inherit Engine
✔ Car CONTAINS Engine
✔ Behavior delegated
#3 Why Use Composition?
✔ Avoid tight coupling
✔ Increase flexibility
✔ Reuse logic cleanly
✔ Change components easily
✔ Better real-world modeling
| Concept | Relationship |
|---|---|
| Inheritance | IS-A |
| Composition | HAS-A |
class Engine:
def start(self):
print("Engine started")
class Car(Engine):
passCar IS-A Engine
class Car:
def __init__(self):
self.engine = Engine()👉 Car HAS-A Engine
✔ Logical
✔ Cleaner design
Inheritance:
Couples classes tightly
Composition:
Connects objects loosely
✔ Easier to modify
✔ Easier to extend
✔ Easier to maintain
class Battery:
def charge(self):
print("Battery charging")
class Phone:
def __init__(self):
self.battery = Battery()
def charge_phone(self):
self.battery.charge()
p = Phone()
p.charge_phone()✔ Phone HAS-A Battery
class Engine:
def __init__(self, power):
self.power = power
def show_power(self):
print(f"Power: {self.power}")
class Car:
def __init__(self, power):
self.engine = Engine(power)
c = Car(200)
c.engine.show_power()Output:
Power: 200
✔ Flexible component injection
class PetrolEngine:
def start(self):
print("Petrol Engine")
class ElectricEngine:
def start(self):
print("Electric Engine")
class Car:
def __init__(self, engine):
self.engine = engine
def start(self):
self.engine.start()
c1 = Car(PetrolEngine())
c2 = Car(ElectricEngine())
c1.start()
c2.start()Output:
Petrol Engine
Electric Engine
✔ EXTREMELY powerful design
👉 Swap behaviors easily
✔ No inheritance needed
✔ Duck typing friendly
Wrong thinking:
"Why not just inherit?"
Inheritance creates rigid hierarchies.
Composition → Flexible systems.
car.engine.start()✔ Works BUT leaks internals
Better design:
car.start()✔ Encapsulation maintained
Bad design:
obj.a.b.c.d.method()✔ Hard to maintain
✔ Use delegation wrappers
Avoid:
A has B
B has A
✔ Creates chaos
✔ Prefer composition over inheritance
✔ Keep components loosely coupled
✔ Hide internal objects
✔ Delegate behavior cleanly
✔ Avoid deep nesting
✔ Use dependency injection
✔ Behavior varies
✔ Components interchangeable
✔ Avoid tight coupling
✔ Real-world modeling
✔ Plugin architectures
✔ Strategy pattern 🔥
✔ True IS-A relationship
✔ Shared core identity
✔ Stable hierarchies
Example:
Dog IS-A Animal
✔ Composition = HAS-A relationship
✔ More flexible than inheritance
✔ Enables dynamic behavior
✔ Promotes loose coupling
✔ Cleaner architecture
✔ Used heavily in real systems
- Convert inheritance → composition
- Build interchangeable engine system
- Hide internal components
- Create plugin architecture
- Trigger deep nesting problem
- Fix using delegation
- Compare flexibility