> ## Documentation Index
> Fetch the complete documentation index at: https://akshanshgusain.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Composition

> OOP of Object-Oriented Design (Study Notes)

**Composition is a design principle where one class contains objects of other classes to reuse functionality instead of inheriting it.**

Inheritance models an “is-a” relationship: a subclass extends a base class and reuses its interface and
implementation . Composition models a “has-a” relationship: a class contains one or more objects of
other classes as members . For example, a Car is a Vehicle (inheritance), but a Car has an Engine
(composition) . Composition tends to yield more modular and flexible designs than deep
inheritance hierarchies .

**Inheritance (is-a):** Only use it when there’s a genuine subtype relationship that obeys Liskov’s
substitution principle. For instance, a Dog class can inherit from Animal . Inheritance can
lead to tight coupling – changes in a base class may break subclasses . A classic pitfall is
giving a subclass behaviors it can’t use: e.g. a Penguin inheriting Bird.fly() behaves
incorrectly .

**Composition (has-a):** A class contains other classes as components. For example, a Car
contains an Engine instance. Composition decouples classes and allows swapping or
reusing parts. You can easily replace one component (say a gas engine with an electric engine)
without altering the container class.

**Guideline:** Favor composition over inheritance unless there’s a clear is-a relationship.
Composition leads to more maintainable, testable code. Inheritance should only be used
when subclasses truly extend base behavior without breaking it

## Inheritance vs Composition

| Feature         | Inheritance                                | Composition                               |
| :-------------- | :----------------------------------------- | :---------------------------------------- |
| **Goal**        | Reuse behavior via "is-a" relationship     | Reuse behavior via "has-a" relationship   |
| **Coupling**    | Tight coupling                             | Loose coupling                            |
| **Flexibility** | Less flexible to change                    | More flexible and modular                 |
| **Code Reuse**  | Inherits all parent behavior               | Reuses specific behavior only when needed |
| **Use When**    | Natural hierarchy exists                   | You want to compose behavior dynamically  |
| **Downsides**   | Fragile base class problem, tight coupling | May involve more boilerplate              |

## When to use Composition?

* You want to combine behaviors flexibly.

* You're designing for loose coupling and testability.

* You want to avoid unintended inheritance side effects.

## Inheritance vs Composition Minimal example

```python Inheritance theme={null}
class Animal:
    def speak(self):
        print("Animal sound")

class Dog(Animal):
    def speak(self):
        print("Woof!")

dog = Dog()
dog.speak()  # Output: Woof!
```

```python Composition theme={null}
class Engine:
    def start(self):
        print("Engine started")

class Car:
    def __init__(self):
        self.engine = Engine()

    def start(self):
        self.engine.start()

car = Car()
car.start()  # Output: Engine started

```

***

### Example: Car and Engine

**Inheritance (bad design):** Using inheritance wrongly can produce inflexible code. In this example, Car inherits from
Engine – implying “Car is an Engine,” which is semantically incorrect. This violates design clarity (a subclass
shouldn’t introduce impossible behavior) and tightly couples Car to Engine.

```python theme={null}
class Engine:
    def start(self):
        print("Engine starting")

class Car(Engine):  # Inheritance misuse: Car is NOT a type of Engine
    def drive(self):
        print("Car driving")

car = Car()
car.start()  # Prints "Engine starting"
```

Although the code runs, it’s conceptually wrong: a Car “is not an” Engine. Inheritance here forces Car to inherit all of
Engine’s behavior, which is inflexible and misleading. Composition (better design): Instead, give Car an Engine object.
Now Car has an engine, which it uses internally. The classes are decoupled: we can modify or replace Engine without
altering Car.

```python theme={null}
class Engine:
    def start(self):
        print("Engine starting")

class Car:
    def __init__(self):
        self.engine = Engine()      # Composition: Car has an Engine
    def start(self):
        print("Car starting")
        self.engine.start()
    def drive(self):
        print("Car driving")

car = Car()
car.start()
```

Now running `car.start()` prints:

```bash theme={null}
Car starting
Engine starting
```

The Car class delegates to its Engine object, embodying a has-a relationship. This design is more realistic and flexible:
we could subclass or swap in a different engine implementation without changing Car. Modern design advice is to “favor
composition over inheritance” for such cases.
