Skip to content
Low Level Design Mastery Logo
LowLevelDesign Mastery

Composition

Strong ownership - parts cannot exist without the whole.

Composition is a “has-a” relationship where one class contains another, and the contained class cannot exist independently. It represents a strong ownership relationship with tied lifecycles.

Composition represents:

  • “Has-a” relationship (strong ownership)
  • Parts cannot exist independently of the whole
  • Parts belong to only one whole
  • Lifecycle dependency - parts are destroyed when whole is destroyed
  • Strong ownership - Container owns the parts
  • Dependent lifecycle - Parts cannot exist without container
  • Single ownership - Parts belong to only one container
  • Filled diamond in UML diagrams
composition_example.py
class Car:
def __init__(self, brand: str, model: str):
self.brand = brand
self.model = model
# Composition - Engine cannot exist without Car
self.engine = Engine() # Created when Car is created
self.wheels = [Wheel() for _ in range(4)] # Created with Car
def start(self):
return self.engine.start()
class Engine:
def __init__(self):
self.running = False
def start(self):
self.running = True
return "Engine started"
class Wheel:
def __init__(self):
self.size = 16
# Engine and Wheels are created and destroyed with Car
car = Car("Toyota", "Camry")
print(car.start()) # "Engine started"
# When car is deleted, engine and wheels are also gone
Diagram
order_composition.py
class Order:
def __init__(self, order_id: str, customer_name: str):
self.order_id = order_id
self.customer_name = customer_name
self.items = [] # Composition - OrderItems belong to Order
self.shipping_address = Address("", "", "", "") # Composition
def add_item(self, product_name: str, quantity: int, price: float):
item = OrderItem(product_name, quantity, price) # Created by Order
self.items.append(item)
def set_shipping_address(self, street, city, state, zip_code):
self.shipping_address = Address(street, city, state, zip_code)
def get_total(self):
return sum(item.get_subtotal() for item in self.items)
class OrderItem:
def __init__(self, product_name: str, quantity: int, price: float):
self.product_name = product_name
self.quantity = quantity
self.price = price
def get_subtotal(self):
return self.quantity * self.price
class Address:
def __init__(self, street: str, city: str, state: str, zip_code: str):
self.street = street
self.city = city
self.state = state
self.zip_code = zip_code
# OrderItems and Address are created with Order
order = Order("ORD-001", "Alice")
order.add_item("Laptop", 1, 999.99)
order.add_item("Mouse", 2, 29.99)
order.set_shipping_address("123 Main St", "SF", "CA", "94102")
print(f"Order total: ${order.get_total():.2f}") # $1059.97
# When order is deleted, items and address are also gone
FeatureCompositionAggregation
OwnershipStrongWeak
LifecycleDependentIndependent
Multi-ownershipNoYes
UML SymbolFilled diamondHollow diamond
ExampleCar → EngineUniversity → Students

Use Composition when:

  • Parts cannot exist without the whole
  • Parts belong to only one whole
  • Lifecycle is tied together
  • Relationship is essential and permanent
  • Parts are created by the whole

Examples:

  • Car → Engine (engine doesn’t exist without car)
  • Order → OrderItems (items don’t exist without order)
  • House → Room (rooms don’t exist without house)
  • Document → Paragraph (paragraphs don’t exist without document)
  • Computer → CPU (CPU doesn’t exist without computer)