Understanding Design Patterns: Abstract Factory
Tags: javascript, designpatterns, cleancode, typescript
Published: 2021-02-28 19:35:32

---
title: Understanding Design Patterns: Abstract Factory
published: true
description: In this article, I am going to describe how the **Abstract Factory Pattern** works and when it should be applied.
tags: javascript, designpatterns, cleancode, typescript
cover_image: https://cdn-images-1.medium.com/max/1400/0*xmzm0tpbHPidsTWY
canonical_url: https://www.carloscaballero.io/understanding-design-patters-abstract-factory
series: pattern-design
---

There are 23 classic design patterns which are described in the original book Design Patterns: Elements of Reusable Object-Oriented Software. These patterns provide solutions to particular problems often repeated in software development.

In this article, I am going to describe how the **Abstract-Factory Pattern** works and when it should be applied.

--

# Abstract Factory: Basic Idea

Wikipedia provides us with the following definition:

>  The [**abstract factory pattern**](https://en.wikipedia.org/wiki/Software_design_pattern) provides a way to encapsulate a group of individual [factories](https://en.wikipedia.org/wiki/Factory_object) that have a common theme without specifying their concrete classes — [Wikipedia](https://en.wikipedia.org/wiki/Factory_method_pattern)

On the other hand, the definition provided by the original book is the following:

>  Provide an interface for creating families of related or dependent objects without specifying their concrete classes — Design Patterns: Elements of Reusable Object-Oriented Software

On many occasions, we need to create different types of objects that are not known a priori from a list of possible objects in which these objects are related in the creation process. The natural tendency is to create a `factoryManager` class that allows us to obtain the different types of objects based on a parameter. However, this solution has two serious drawbacks that we will describe throughout this article:

1. It breaks the principle of *Open-Closed Principle* which gives code that is not clean; and that it is not easy to maintain when the software scales.

2. The `factoryManager` class is attached to all types of objects that you want to build, creating code known as spaghetti code.

This problem and its solution have been dealt with in the article in which the **Factory-Method** design pattern is presented, which allows solving this problem when the creation of objects is simple and they are not related to each other. Therefore, it is recommended that you read this article first to later address this **AbstractFactory** pattern.

The **Abstract Factory** pattern allows for a clearer code, since it avoids the previously mentioned problem. The UML diagram of this pattern is as follows:

![Diagrama UML del libro Design Patterns: Elements of Reusable Object-Oriented Software.](https://cdn-images-1.medium.com/max/2000/1*Hq1dVINI67d-_IQjco5-Sw.png)


The classes that comprise this pattern are the following:

* **AbstractProductA** and **AbstractProductB** are the interfaces for a set of products of the same type but of a different family. In other words, all the products that implement the `AbstractProductA` class belong to the same product type, although they will be organized into different families. This type of object will be better understood in the concrete example that follows.

* **ProductA1**, **ProductA2**, **ProductB1** and **ProductB** are concrete implementations of each type of `AbstractProduct`.

* **AbstractFactory** is the interface that declares the set of creation methods for each of the concrete factories (`ConcreteFactory1` and `ConcreteFactory2`).

* **ConcreteFactory1** and **ConcreteFactory2** implement the creation methods of the `AbstractFactory` class for each of the product families.


---

# Abstract Factory Pattern: When To Use
1. The problems solved by **Abstract Factory** are similar to those solved by the **Factory-Method** pattern, but with greater abstraction in the types of objects that need to be created. Therefore, in the case of **Abstract Factory** it is required to work with several families of products related to each other rather than in a set of products.

2. **The family of objects with which the client must work is not known a priori**. Rather, this knowledge depends directly on the interaction of another user with the system (end user or system).

3. In the event that it is **necessary to extend the internal components** (the number of families and objects that are created) without having to have the code coupled, but rather have interfaces and abstractions that allow to easily extend with factories and specific products.

---

# Abstract Factory Pattern: Advantages and Disadvantages
The *Abstract Factory* pattern has a number of advantages that can be summarized in the following points:

* Compatibility between products created by the same *factory* class is guaranteed.

* **Clean code** as the *Open-Closed Principle* is guaranteed since new product families can be introduced without breaking the existing code.

* **Cleaner code** since the *Single Responsibility Principle (SRP)* is respected since the responsibility of creating the concrete product is transferred to the concrete creator class instead of the client class having this responsibility.
* **Cleaner code** because the *Single Responsibility Principle (SRP)* is respected since the responsibility of creating the concrete product is transferred to the concrete creator class instead of the client class having this responsibility.

However, the main drawback of the *abstract factory* pattern, like most design patterns, is that there is an increase in complexity in the code, and an increase in the number of classes required for the code. Although, this disadvantage is well known when applying design patterns for it is the price to pay for gaining abstraction in the code.


---

# Abstract Factory Pattern Examples

Next, we are going to illustrate two examples of application of the *Abstract Factory* pattern:

 1. Basic structure of the **Abstract Factory** pattern. In this example we are going to translate the theoretical UML diagram into TypeScript code to identify each of the classes involved in the pattern.

 2. Creation of **characters in a video game**. Let's think of the classic WoW (*World of Warcraft*) in which the player can have a set of objects depending on the race they choose. For example, we will have the races: Humans, Orcs and Magicians; which will have weapons and armor (products) that will be different depending on the race (the family of objects).


The following examples will show the implementation of this pattern using **TypeScript**. We have chosen TypeScript to carry out this implementation rather than JavaScript — the latter lacks interfaces or abstract classes so the responsibility of implementing both the interface and the abstract class would fall on the developer.


# Example 1: Basic structure of the abstract factory pattern
In this first example, we’re going to translate the theoretical UML diagram into TypeScript to test the potential of this pattern. This is the diagram to be implemented:


![Class diagram of the basic structure of the abstract factory pattern.](https://cdn-images-1.medium.com/max/2646/1*4kc8r8jedSbJ6JDo1vkI4g.jpeg)

First, we are going to define the interfaces (`AbstractProductA` and `AbstractProductB`) that define the types of concrete products that we want to create for the different families. In our concrete example, to simplify the understanding of the pattern as much as possible, only one method has been defined for each of these interfaces: `usefulFunctionA` and `usefulFunctionB` respectively.


```javascript
export interface AbstractProductA {
  usefulFunctionA(): string;
}
```

```javascript
export interface AbstractProductB {
  usefulFunctionB(): string;
}
```

The next step is to define the specific products that implement each of these interfaces. In our case, two concrete objects will be implemented for each of these abstract classes. For the first interface (`AbstractProductA`) the classes` ConcreteProductA1` and `ConcreteProductA2` are implemented, while for the second interface (`AbstractProductB`) the classes `ConcreteProductB1` and `ConcreteProductB2` are implemented.


```javascript
import { AbstractProductA } from "./abstract-productA";

export class ConcreteProductA1 implements AbstractProductA {
  public usefulFunctionA(): string {
    return "The result of the product A1.";
  }
}
```

```javascript
import { AbstractProductA } from "./abstract-productA";

export class ConcreteProductA2 implements AbstractProductA {
  public usefulFunctionA(): string {
    return "The result of the product A2.";
  }
}
```

```javascript
import { AbstractProductB } from "./abstract-productB";

export class ConcreteProductB1 implements AbstractProductB {
  public usefulFunctionB(): string {
    return "The result of the product B1.";
  }
}
```

```javascript
import { AbstractProductB } from "./abstract-productB";

export class ConcreteProductB2 implements AbstractProductB {
  public usefulFunctionB(): string {
    return "The result of the product B2.";
  }
}
```

Once the structure of classes related to the creation of products has been defined, we proceed to define the structure of classes related to the creation of factories in charge of creating these objects. Therefore, first the abstract class `AbstractFactory` is defined in which the methods in charge of creating the concrete objects by the concrete factories are defined. However, note that these methods return the abstract classes from each of the `AbstractProductA` and` AbstractProductB` products.


```javascript
import { AbstractProductA } from "./abstract-productA";
import { AbstractProductB } from "./abstract-productB";

export interface AbstractFactory {
  createProductA(): AbstractProductA;
  createProductB(): AbstractProductB;
}
```

Finally, it would be necessary to define the concrete factories, in which the concrete classes are instantiated. In this first example, the `ConcreteFactory1` factory will be in charge of instantiating the concrete objects of family 1 (`ConcreteProductA1` and `ConcreteProductB1`) and the `ConcreteFactory2` factory will be in charge of instantiating the concrete objects of family 2 (`ConcreteProductA2` and `ConcreteProductB2`).


```javascript
import { AbstractFactory } from "./abstract-factory";
import { AbstractProductA } from "./abstract-productA";
import { AbstractProductB } from "./abstract-productB";
import { ConcreteProductA1 } from "./concrete-productA1";
import { ConcreteProductB1 } from "./concrete-productB1";

export class ConcreteFactory1 implements AbstractFactory {
  public createProductA(): AbstractProductA {
    return new ConcreteProductA1();
  }

  public createProductB(): AbstractProductB {
    return new ConcreteProductB1();
  }
}
```

```javascript
import { AbstractFactory } from "./abstract-factory";
import { AbstractProductA } from "./abstract-productA";
import { AbstractProductB } from "./abstract-productB";
import { ConcreteProductA2 } from "./concrete-productA2";
import { ConcreteProductB2 } from "./concrete-productB2";

export class ConcreteFactory2 implements AbstractFactory {
  public createProductA(): AbstractProductA {
    return new ConcreteProductA2();
  }

  public createProductB(): AbstractProductB {
    return new ConcreteProductB2();
  }
}
```

Although it is not a direct part of the pattern, it would be necessary to see the execution of the pattern by the `Client/Context` class. In this case, the `ClientCode` method does not need to know the specific factory to create the products, but receiving an object of the `AbstractFactory` class as a parameter is sufficient to execute the `CreateProductA` and `CreateProductB` methods.


```javascript
import { AbstractFactory } from "./abstract-factory";
import { ConcreteFactory1 } from "./concrete-factory1";
import { ConcreteFactory2 } from "./concrete-factory2";

function clientCode(factory: AbstractFactory) {
  const productA = factory.createProductA();
  const productB = factory.createProductB();

  console.log(productA.usefulFunctionA());
  console.log(productB.usefulFunctionB());
}

console.log("Client: Testing client code with ConcreteFactory1");
clientCode(new ConcreteFactory1());

console.log("----------------");

console.log("Client: Testing the same client code with ConcreteFactory2");
clientCode(new ConcreteFactory2());
```

---
# Example 2 - Creation of Heroes equipment of a video game

We have already seen the theoretical example of this pattern, so you already understand the responsibilities of each of the classes of this pattern. Now, we are going to illustrate a real example in which we will identify each of the classes of this design pattern.

Our problem consists of the representation of the equipment of different heroes or characters in a video game. We will focus on the classic WoW video game (*World of Warcraft*), in which the heroes are divided into three races: Humans, orcs and wizards. Each of these heroes can have different armor (`armor`) and weapons (`weapon`) that vary depending on the race. Therefore, we can already identify that the products to be built will be the different types of armor and weapons, and the product families are the product family for a human, orc and wizard.

Therefore, following the same methodology as the one we have presented in the previous examples, we are going to start by looking at the UML diagram that will help us identify each of the parts of this pattern.


![Class Diagram: Video Game](https://cdn-images-1.medium.com/max/3298/1*2bsCUIHyKdpbarsKMWtF4w.jpeg)

A priori, the class design of this problem may be impressive, but if we have understood the example of the basic structure of this pattern, we will understand this example perfectly.

We will start by creating each of the specific product types. That is, the first thing that is defined is the interface that models a weapon (`weapon`).



```javascript
export interface Weapon {
  usefulFunction(): string;
}
```

To simplify the example, only one method called `usefulFunction` has been defined for each one of the `weapons`. Thus, the specific weapons that are defined are `sword`, `axe` and `mage-fireball`.



```javascript
import { Weapon } from "./weapon.interface";

export class Sword implements Weapon {
  public usefulFunction(): string {
    return "The result of the Sword";
  }
}
```

```javascript
import { Weapon } from "./weapon.interface";

export class Axe implements Weapon {
  public usefulFunction(): string {
    return "The result of the Axe";
  }
}
```

```javascript
import { Weapon } from "./weapon.interface";

export class MageFireball implements Weapon {
  public usefulFunction(): string {
    return "The result of the MageFireball";
  }
}
```

In the same way that the `weapon` has been defined, the different armor (`armor`) is defined. In this specific case, we have created a collaboration between the armor (`armor`) and the weapon (`weapon`) through a method called `usefulFunctionWithWeapon` to illustrate that the objects can be related to each other. The most important thing to note is that the collaborator parameter is of the abstract class `Weapon`, rather than working with concrete classes.



```javascript
import { Weapon } from "../weapons/weapon.interface";

export interface Armor {
  usefulFunction(): string;
  usefulFunctionWithWeapon(collaborator: Weapon): string;
}
```

The specific armors that we need for our problem are `BodyArmor`,`OrcArmor` and `Cloak` that will be created by each of the object families according to the Hero's race.


```javascript
import { Armor } from "./armor-interface";
import { Weapon } from "../weapons/weapon.interface";

export class BodyArmor implements Armor {
  public usefulFunction(): string {
    return "The result of the BodyArmor";
  }

  public usefulFunctionWithWeapon(collaborator: Weapon): string {
    const result = collaborator.usefulFunction();
    return `The result of the BodyAmor collaborating with the (${result})`;
  }
}
```

```javascript
import { Armor } from "./armor-interface";
import { Weapon } from "../weapons/weapon.interface";

export class OrcArmor implements Armor {
  public usefulFunction(): string {
    return "The result of the OrcArmor";
  }

  public usefulFunctionWithWeapon(collaborator: Weapon): string {
    const result = collaborator.usefulFunction();
    return `The result of the OrcAmor collaborating with the (${result})`;
  }
}
```

```javascript
import { Armor } from "./armor-interface";
import { Weapon } from "../weapons/weapon.interface";

export class Cloak implements Armor {
  public usefulFunction(): string {
    return "The result of the Cloak";
  }

  public usefulFunctionWithWeapon(collaborator: Weapon): string {
    const result = collaborator.usefulFunction();
    return `The result of the Cloak collaborating with the (${result})`;
  }
}
```

Up to this point, the specific products that we want to create in our video game have been defined but the creation rules have not been established. It is the specific factories that will be in charge of creating the specific products according to the Hero's race. The first class to define is the abstract class `AbstractFactory` which defines the `createWeapon` and `createAmor` methods that are responsible for creating the abstract `Weapon` and `Armor` products. Notice that all the code up to this point has made use of abstract classes.



```javascript
import { Armor } from "./armor/armor-interface";
import { Weapon } from "./weapons/weapon.interface";

export interface AbstractFactory {
  createWeapon(): Weapon;
  createArmor(): Armor;
}
```

At this time, we have to implement the concrete factories `HumanFactory`, `OrcFactory` and `MageFactory` in which the creator methods are implemented with the concrete products based on the race of the hero.



```javascript
import { AbstractFactory } from "./abstract-factory";
import { Armor } from "./armor/armor-interface";
import { BodyArmor } from "./armor/body-armor.model";
import { Sword } from "./weapons/sword.model";
import { Weapon } from "./weapons/weapon.interface";

export class WarriorFactory implements AbstractFactory {
  public createWeapon(): Weapon {
    return new Sword();
  }

  public createArmor(): Armor {
    return new BodyArmor();
  }
}
```

```javascript
import { AbstractFactory } from "./abstract-factory";
import { Armor } from "./armor/armor-interface";
import { Axe } from "./weapons/axe.model";
import { OrcArmor } from "./armor/orc-armor.model";
import { Weapon } from "./weapons/weapon.interface";

export class OrcFactory implements AbstractFactory {
  public createWeapon(): Weapon {
    return new Axe();
  }

  public createArmor(): Armor {
    return new OrcArmor();
  }
}
```

```javascript
import { AbstractFactory } from "./abstract-factory";
import { Armor } from "./armor/armor-interface";
import { Cloak } from "./armor/cloak.model";
import { MageFireball } from "./weapons/mage-fireball.model";
import { Weapon } from "./weapons/weapon.interface";

export class MageFactory implements AbstractFactory {
  public createWeapon(): Weapon {
    return new MageFireball();
  }

  public createArmor(): Armor {
    return new Cloak();
  }
}
```

To conclude the example of creating the equipment of our heroes, we are going to implement the `Client/Context` class.



```javascript
import { AbstractFactory } from "./abstract-factory";
import { MageFactory } from "./mage-factory";
import { OrcFactory } from "./orc-factory";
import { WarriorFactory } from "./warrior-factory";

function clientCode(factory: AbstractFactory) {
  const sword = factory.createWeapon();
  const armor = factory.createArmor();

  console.log(armor.usefulFunction());
  console.log(armor.usefulFunctionWithWeapon(sword));
}

console.log("Client: WarriorFactory");
clientCode(new WarriorFactory());

console.log("----------------");

console.log("Client: OrcFactory");
clientCode(new OrcFactory());

console.log("----------------");

console.log("Client: MageFactory");
clientCode(new MageFactory());
```
Finally, I’ve created two `npm scripts`, through which the code presented in this article can be executed:

```javascript
    npm run example1
    npm run example2
```


GitHub Repo available [here](https://github.com/Caballerog/blog/tree/master/abstract-factory-pattern).

# Conclusion

**Abstract Factory** is a design pattern that allows respecting the *Open-Closed Principle* principle and delegates the responsibility for creating objects to specific classes (concrete factories) using polymorphism. This allows us to have a much cleaner and more scalable code.

This pattern solves the problem that arises when it is necessary to create different types of objects that depend on the interaction of a client with the system in which it is not known beforehand which object the client will create. Furthermore, these objects are related by object families, in such a way that it allows to have them separated by context or object types when using different factories.

Another advantage of this pattern is that the system is not coupled to a set of concrete classes, but the client only communicates with abstract classes allowing to have a much more maintainable code when the software scales.

Finally, the most important thing about this pattern is not the concrete implementation of it, but being able to recognize the problem that this pattern can solve, and when it can be applied. The specific implementation is the least of it, since it will vary depending on the programming language used.