# Abstract Factory

## [About](https://refactoring.guru/design-patterns/abstract-factory)

It provides an interface/contract to create family of related objects. *(Like an interface for a* `Factory`*)*

{% hint style="success" %}
Use `Absctract Factories`, when you don't want to couple your code to a distinct one, the each distinct Factory will always be injected.

This also means that `Abstract Factories` cannot work statically.
{% endhint %}

{% hint style="success" %}
On the contrary to `Static Factory Methods`, where the `create()` will receive as parameter the type of distinct object it should create, `Abstract Factories` will decide which distinct object by dependincy injection.
{% endhint %}

{% hint style="danger" %}
As a downside, it will require more bureocracy, as more interfaces will have to be made.

Also you can't work with the Factory statically, and each distinct Factory will have to be instanciated.
{% endhint %}

Explicitly declare interface/class for each distinct object from the same family.

{% code title="Chair.ts" %}

```typescript
interface Chair {
    color: string;
    price(): number;
}

class ChairOffice implements Chair {
    color: string;
    price(): number { ... }
}

class ChairTable implements Chair {
    color: string;
    price(): number { ... }
}
```

{% endcode %}

Declare the `Absctract Factory` interface. (*This interface has the creation method that returns the abstract type)*

Then on each concrete `Factory` class, the creation method will return the distinct object.

{% code title="Factory.ts" %}

```typescript
interface ChairFactory {
    createChair(): Chair;
}

class ChairOfficeFactory implements ChairFactory {
    createChair(): Chair { return new ChairOffice(); }
}

class ChairTableFactory implements ChairFactory {
    createChair(): Chair { return new ChairTable(); }
}
```

{% endcode %}

Wherever you use the `Factory`, you always use the `Abstract` one.

The distinct `Factory` will then be injected.

{% code title="Usecase1.ts" %}

```typescript
class Usecase1 {
    // The factory that you get is the ChairFactory instance that was injected. 
    constructor(readonly factory: ChairFactory) {}

    execute() {
        // If `ChairOfficeFactory` was injected
        const officeChair = factory.createChair();
        
        // If `ChairTableFactory` was injected
        const tableChair = factory.createChair();
    }
}
```

{% endcode %}
