# Composition vs Inheritance  in Object-Oriented Programming - JavaScript example

## Composition and Inheritance

There are two main ways to reuse code in object-oriented programming: composition and inheritance. Both have their advantages and disadvantages, and the choice of which to use in a given situation is a design decision.

## What is Composition?

Composition is the act of combining objects to create a new object. The new object contains references to the other objects and can delegate behavior to them. This is often seen as a has-a relationship. For example, a `Person` has an `Address`, so we can say that the person is composed of an address. 

Let's take a look at how we could express it in code:

```javascript
class Address {
  constructor(street, city, state) {
    this.street = street;
    this.city = city;
    this.state = state;
  }
}

class Person {
  constructor(name, address) {
    this.name = name;
    this.address = address;
  }
}

const address = new Address('123 Main St', 'New York', 'NY');
const person = new Person('John Smith', address);

console.log(person.address.street); // 123 Main St
```

In this example, `Person` is composed of its own properties and `Address` that is  being passed to the constructor.

### Pros and cons of the Composition

The advantage of composition is that it is very flexible. We can change the behavior of our `Person` by changing the `Address` object it uses (e.g add postcode to printed value). We can also create different types of `Addresses`, and our `Person` class doesn’t need to know anything about them. This also makes our code more reusable as we can use individual components in different contexts.

There are also some disadvantages to using composition in programming. First, it can require more effort to design and implement a compositional system than a monolithic one. It can also lead to code that is more difficult to debug and optimize, as the dependencies between components can be complex.

## What is Inheritance?

Inheritance is the act of creating a new class that is a specialized version of an existing class. The new class inherits the behavior of the existing class, and can also add new behavior of its own. This is often seen as an is-a relationship. For example, a `Dog` is a type of `Animal`.

Code example for inheritance:

```javascript
class Animal {
  constructor(name) {
    this.name = name;
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }
}

const dog = new Dog('Buddy', 'Golden Retriever');

console.log(dog.name); // Buddy
console.log(dog.breed); // Golden Retriever
```

In the example above, the `Dog` class is derived from the Animal class. The `Dog` class inherits the name property from the `Animal` class.

### Pros and cons of the Inheritance

The advantage of inheritance is that it can be used to model real-world relationships. Our `Dog` is a type of `Animal`, so it makes sense that it would inherit from the `Animal` class. It allows you to reuse code from a parent class in a child class. This can save you a lot of time and effort when you are developing a new class. Inheritance can also make your code more flexible and extensible. If you need to add a new method to a child class, you can simply override the parent class's method.

However, inheritance can also make your code more complex and difficult to understand. If a child class inherits from multiple parent classes, it can be hard to keep track of which methods are inherited from which class. This can make your code more difficult to maintain and debug. Additionally, inheritance can sometimes lead to unexpected behavior. If a child class inherits a method from a parent class that has been overridden in the child class, the child class's method will be called instead of the parent class's method.

## Which one to use?

As usual in programming - it depends.

In general, you should use inheritance when you have a clear, linear relationship between the child and parent classes. For example, if you have a class hierarchy where each class adds a new layer of functionality on top of the previous one, inheritance makes sense.

Composition, on the other hand, is more flexible. It allows you to build objects from other objects, without having to follow a strict linear hierarchy. This can be useful when you want to reuse existing code or when the relationship between the child and parent classes is more complex.

There are pros and cons to both inheritance and composition, and the best way to choose between them is to understand when each one is appropriate.
