cv.cm

Coding · Design patterns

Abstract Factory pattern explained with examples

5 min read

Short answer

Abstract Factory is a creational design pattern that provides an interface for creating families of related objects without specifying their concrete classes. Client code receives a factory object, such as a LightThemeFactory or DarkThemeFactory, and asks it for each product (a button, a dialog). Because one factory creates the whole family, the products always match each other, and you can switch families by passing a different factory.

Intent

Provide an interface for creating families of related or dependent objects without specifying their concrete classes. Abstract Factory is one of the five creational patterns in the Gang of Four (GoF) book, where it is also known as Kit.

The problem it solves

Imagine a reporting app that can render output for two targets: a web page and a plain-text terminal. Each target needs its own versions of several components: a heading, a table and a warning box. The web heading must not be mixed with the terminal table, or the output breaks.

If the report code calls new HtmlHeading() and new TextTable() directly, it is tied to concrete classes, the target choice is spread across many lines, and nothing stops someone from mixing families. Abstract Factory puts all creation for one family behind one object, so the choice is made in exactly one place.

Structure and participants

ParticipantResponsibilityIn the example
AbstractFactoryDeclares one creation method per product type.UiFactory
ConcreteFactoryImplements the creation methods for one family.HtmlFactory, TextFactory
AbstractProductInterface for one kind of product.Heading, Alert
ConcreteProductA product of a specific family.HtmlHeading, TextAlert
ClientUses only the abstract factory and abstract product interfaces.renderReport

TypeScript implementation

interface Heading { render(text: string): string; }
interface Alert { render(text: string): string; }

interface UiFactory {
  createHeading(): Heading;
  createAlert(): Alert;
}

class HtmlFactory implements UiFactory {
  createHeading(): Heading { return { render: (t) => `<h1>${t}</h1>` }; }
  createAlert(): Alert { return { render: (t) => `<div class="alert">${t}</div>` }; }
}

class TextFactory implements UiFactory {
  createHeading(): Heading { return { render: (t) => `${t}\n${"=".repeat(t.length)}` }; }
  createAlert(): Alert { return { render: (t) => `[!] ${t}` }; }
}

// The client knows only the interfaces.
function renderReport(ui: UiFactory): string {
  const heading = ui.createHeading();
  const alert = ui.createAlert();
  return [heading.render("Sales"), alert.render("2 orders failed")].join("\n");
}

const target: string = "text"; // e.g. from a command-line flag
const factory: UiFactory = target === "html" ? new HtmlFactory() : new TextFactory();
console.log(renderReport(factory));
// Sales
// =====
// [!] 2 orders failed

The only place that names a concrete class is the line that chooses the factory. renderReport works with any family, and it cannot accidentally mix HTML and text pieces, because it gets all its products from the same factory.

In a real program the products would usually be classes with more methods. Object literals keep the example short; the structure is the same.

When to use it, and when not to

Use Abstract Factory when:

  • The system must work with several families of related products, and products from different families must not be combined (UI themes, operating-system widgets, database drivers with matching connection and command objects).
  • You want to choose the family once, at configuration time, and keep the rest of the code independent of it.
  • You want tests to supply a family of fake objects through one factory.

Avoid it when:

  • There is only one family. A direct new, or one factory function, is simpler.
  • Product types change often. Adding a new kind of product, such as createTable(), forces you to change the factory interface and every concrete factory. This is the main weakness the GoF book lists.

Abstract Factory versus Factory Method

AspectFactory MethodAbstract Factory
CreatesOne productA family of related products
MechanismA subclass overrides one creation methodThe client receives a factory object with several creation methods
Relies onInheritanceComposition
Easy to addA new product variant (new subclass)A new family (new factory class)
Hard to addLittle; each creator is independentA new product type (every factory changes)

The two are often combined: each creation method of a concrete factory is itself a factory method.

Real-world uses

  • Java XML APIs: DocumentBuilderFactory and TransformerFactory are abstract classes. newInstance() locates a concrete implementation, and the code that uses it depends only on the abstract types.
  • Java's JDBC API works in a similar way: a database driver supplies matching Connection, Statement and ResultSet implementations, and application code uses only the interfaces.
  • The GoF book's own example is a user-interface toolkit that supports several look-and-feel standards, with one factory per standard creating matching scroll bars, windows and buttons.

Related patterns

  • Factory Method: concrete factories often implement their creation methods as factory methods.
  • Prototype: a factory can be configured with prototype objects and create products by copying them, which avoids one factory subclass per family.
  • Singleton: an application usually needs only one instance of each concrete factory.
  • Builder: also hides construction, but builds one complex object step by step, while Abstract Factory returns finished products immediately.
  • Bridge: an abstract factory can create and configure the implementation side of a bridge.

FAQ

What is a family of products?

A set of objects designed to be used together, such as the button, menu and dialog of one UI theme. Mixing products from different families would give inconsistent or broken results.

How do I add a new product type to an Abstract Factory?

You add a creation method to the factory interface and implement it in every concrete factory. That is why the pattern fits best when the set of product types is stable.

Is Abstract Factory the same as dependency injection?

No, but they work well together. Dependency injection supplies an object from outside; Abstract Factory is a kind of object you can inject when the client needs to create several related objects itself.

Can an Abstract Factory be a function instead of a class?

Yes. In TypeScript a factory can be a plain object of creation functions that satisfies the factory interface. The pattern is about the interface and the families, not about classes.

All coding tutorials