Skip to main content

What is The Abstract Factory Pattern

Abstract Factory is a creational design pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes.

To visualize the class diagram, you may want to copy this code to a Markdown file or use online Mermaid live editor.

This implementation is a concrete example of the Abstract Factory design pattern. Here is a brief description:

  1. Interfaces (IProductA, IProductB, and IFactory): These define the contracts for the products and the factory. Each product interface has methods that need to be implemented by any concrete product. The factory interface has methods for creating instances of the products.

  2. Concrete Products (ProductA and ProductB): These are the implementations of the product interfaces. Each product has a specific operation (i.e., operationA and operationB). Additionally, ProductB has a combinedOperation method that collaborates with an instance of ProductA.

  3. Concrete Factory (Factory1): This is the implementation of the factory interface. It is responsible for creating and returning instances of the products (ProductA and ProductB).

  4. Client Code: The client code takes an instance of a factory and uses its methods to create products. It does not need to be aware of the concrete classes of the products it works with, thanks to the abstraction provided by the interfaces and the factory.

Classic Implementation

The Abstract Factory pattern helps in maintaining consistency among products that are intended to be used together, and it promotes loose coupling by keeping details about product types hidden from the client code.

interface IProductA {
operationA(): string;
}

interface IProductB {
operationB(): string;

combinedOperation(collaborator: IProductA): string;
}

interface IFactory {
createProductA(): IProductA;

createProductB(): IProductB;
}

class ProductA implements IProductA {
public operationA(): string {
return "The result of the operation A1.";
}
}

class ProductB implements IProductB {
public operationB(): string {
return "The result of the operation B1.";
}

public combinedOperation(collaborator: IProductA): string {
const result = collaborator.operationA();
return `The result of the B1 collaborating with the (${result})`;
}
}

class Factory1 implements IFactory {
public createProductA(): IProductA {
return new ProductA();
}

public createProductB(): IProductB {
return new ProductB();
}
}

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

console.log(productB.operationB());
console.log(productB.combinedOperation(productA));
}

console.log("Client: Testing client code with the factory...");
clientCode(new Factory1());
TypeScript Course Instructor Image
TypeScript Course Instructor Image

Time To Transition From JavaScript To TypeScript

Level Up Your TypeScript And Object Oriented Programming Skills. The only complete TypeScript course on the marketplace you building TypeScript apps like a PRO.

SEE COURSE DETAILS

Why Use The Abstract Factory Pattern

The Abstract Factory pattern It is typically used when a system needs to be independent from the way the objects it creates are generated or it needs to work with multiple types of objects.

Here are some indicators that might suggest the Abstract Factory pattern could be appropriate:

  1. Interrelated Dependencies: If you have a family of related products and you need to ensure that a client always uses objects that belong together, you might consider the Abstract Factory pattern. The pattern allows you to enforce this constraint automatically.

  2. Switching Product Families: If you need to provide a way to swap out entire "families" of objects, an Abstract Factory can make this easier. For example, your system could support multiple look-and-feel standards (like different widget styles), and you want to allow switching between them.

  3. Encapsulating Complex Creation Logic: If creating an object involves a complex process that has dependencies on other objects or on some configuration, encapsulating this process in an Abstract Factory can make your code easier to read and maintain.

  4. Isolating Concrete Classes: If you want to isolate the concrete classes used in your application from the code that constructs the objects, an Abstract Factory can help. The factory encapsulates the responsibility and the process of creating product objects, and it isolates clients from implementation details.

  5. Consistent Object Creation: If your code has dependencies on specific types of objects that need to be created together and you want to enforce consistency, Abstract Factory is a good choice.

  6. Supporting Multiple Architectures: If your software needs to run in different environments that require different implementations of a set of related objects, Abstract Factory allows you to encapsulate these differences and make your software more flexible and adaptable.

Just like with other patterns, it's essential to consider the trade-offs and make sure that the Abstract Factory pattern is a good fit for your specific problem. Overusing or misusing design patterns can lead to unnecessary complexity and can make your code harder to understand and maintain.

Comparing Factory And Abstract Factory

The Factory Method and Abstract Factory design patterns are both creational design patterns that deal with the problem of creating objects without specifying the exact class of the object that will be created. However, they solve this problem in different ways and their use cases differ.

Factory Method Pattern:

  • Factory method deals with the problem of creating objects without specifying the exact class of object that will be created.
  • It provides a simple decision making class that returns one of several possible subclasses of an abstract base class depending on the data that are provided.
  • It's about creating products which are related by a common theme.
  • It relies on inheritance as it is typically implemented in a subclass selecting which class to instantiate.
  • Use the Factory Method pattern when you don't know beforehand the exact types and dependencies of the classes your code should work with.

Abstract Factory Pattern:

  • Abstract Factory is a super-set of Factory method pattern. It's like a factory of factories.
  • It provides an interface for creating families of related or dependent objects without specifying their concrete classes.
  • It returns the factory of classes. Thus, the Abstract Factory is the interface to create factory classes.
  • It encapsulates a group of individual factories with a common goal.
  • Abstract Factory relies on object composition, as object creation is implemented in methods exposed in the factory interface.
  • Use the Abstract Factory pattern when your code needs to work with various families of related products, but you don’t want it to depend on the concrete classes of those products—they might be unknown beforehand or you simply want to allow for future extensibility.

In short, the Factory Method is a specialization of an object creation code but the Abstract Factory is a specialization of the factory itself.

What Can You Do Next 🙏😊

If you liked the article, consider subscribing to Cloudaffle, my YouTube Channel, where I keep posting in-depth tutorials and all edutainment stuff for software developers.

YouTube @cloudaffle