Aller au contenu

Abstract Factory - A Design Pattern for Family Creation

Ce contenu n’est pas encore disponible dans votre langue.

The Abstract Factory is a creational design pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes. It ensures that created objects are compatible with each other.


Abstract Factory is a super-factory that creates other factories. It provides a way to encapsulate a group of individual factories with a common theme without specifying their concrete classes, ensuring consistency among products.


Cross-Platform UI

Create UI elements for different operating systems (Windows, Mac, Linux).

Theme Systems

Generate consistent UI components for different themes (Dark, Light).

Database Adapters

Create database-specific connection, query, and result objects.

Document Formats

Generate complete document sets in different formats (PDF, Word, HTML).

Advantages ✅Disadvantages ❌
Ensures product compatibility.Complex to implement and understand.
Isolates concrete classes.Difficult to support new product types.
Promotes consistency among products.Increases number of classes.
Follows Single Responsibility Principle.Can be overkill for simple scenarios.

The pattern consists of five main components:

  1. Abstract Products: Interfaces for different types of products
  2. Concrete Products: Specific implementations of abstract products
  3. Abstract Factory: Interface for creating abstract products
  4. Concrete Factories: Implement creation methods for specific product families
  5. Client: Uses only abstract interfaces

// Abstract Products
interface Button {
render(): string;
onClick(): void;
}
interface Checkbox {
render(): string;
toggle(): void;
}
// Concrete Products - Windows
class WindowsButton implements Button {
render(): string {
return "Rendering Windows button";
}
onClick(): void {
console.log("Windows button clicked");
}
}
class WindowsCheckbox implements Checkbox {
render(): string {
return "Rendering Windows checkbox";
}
toggle(): void {
console.log("Windows checkbox toggled");
}
}
// Concrete Products - Mac
class MacButton implements Button {
render(): string {
return "Rendering Mac button";
}
onClick(): void {
console.log("Mac button clicked");
}
}
class MacCheckbox implements Checkbox {
render(): string {
return "Rendering Mac checkbox";
}
toggle(): void {
console.log("Mac checkbox toggled");
}
}
// Abstract Factory
interface GUIFactory {
createButton(): Button;
createCheckbox(): Checkbox;
}
// Concrete Factories
class WindowsFactory implements GUIFactory {
createButton(): Button {
return new WindowsButton();
}
createCheckbox(): Checkbox {
return new WindowsCheckbox();
}
}
class MacFactory implements GUIFactory {
createButton(): Button {
return new MacButton();
}
createCheckbox(): Checkbox {
return new MacCheckbox();
}
}
// Client Code
class Application {
private button: Button;
private checkbox: Checkbox;
constructor(factory: GUIFactory) {
this.button = factory.createButton();
this.checkbox = factory.createCheckbox();
}
render(): void {
console.log(this.button.render());
console.log(this.checkbox.render());
}
}
// Usage
const os = "Windows"; // or "Mac"
const factory: GUIFactory = os === "Windows"
? new WindowsFactory()
: new MacFactory();
const app = new Application(factory);
app.render();

types/theme.ts
import { Component } from 'vue';
export interface ThemeFactory {
createButton(): Component;
createCard(): Component;
createInput(): Component;
}
// factories/LightThemeFactory.ts
import { ThemeFactory } from '../types/theme';
import LightButton from '../components/light/LightButton.vue';
import LightCard from '../components/light/LightCard.vue';
import LightInput from '../components/light/LightInput.vue';
export class LightThemeFactory implements ThemeFactory {
createButton() { return LightButton; }
createCard() { return LightCard; }
createInput() { return LightInput; }
}
// factories/DarkThemeFactory.ts
import { ThemeFactory } from '../types/theme';
import DarkButton from '../components/dark/DarkButton.vue';
import DarkCard from '../components/dark/DarkCard.vue';
import DarkInput from '../components/dark/DarkInput.vue';
export class DarkThemeFactory implements ThemeFactory {
createButton() { return DarkButton; }
createCard() { return DarkCard; }
createInput() { return DarkInput; }
}
<script setup lang="ts">
import { ref, computed } from 'vue';
import { LightThemeFactory } from './factories/LightThemeFactory';
import { DarkThemeFactory } from './factories/DarkThemeFactory';
const isDark = ref(false);
const factory = computed(() =>
isDark.value ? new DarkThemeFactory() : new LightThemeFactory()
);
const ButtonComponent = computed(() => factory.value.createButton());
const CardComponent = computed(() => factory.value.createCard());
</script>
<template>
<div>
<button @click="isDark = !isDark">Toggle Theme</button>
<component :is="ButtonComponent">Click Me</component>
<component :is="CardComponent">
<p>Card content</p>
</component>
</div>
</template>

// Abstract Products
interface Connection {
connect(): void;
disconnect(): void;
}
interface Query {
execute(sql: string): void;
}
interface Result {
fetch(): any[];
}
// MySQL Products
class MySQLConnection implements Connection {
connect(): void {
console.log("Connecting to MySQL database");
}
disconnect(): void {
console.log("Disconnecting from MySQL");
}
}
class MySQLQuery implements Query {
execute(sql: string): void {
console.log(`Executing MySQL query: ${sql}`);
}
}
class MySQLResult implements Result {
fetch(): any[] {
return [{ id: 1, name: "MySQL Data" }];
}
}
// PostgreSQL Products
class PostgreSQLConnection implements Connection {
connect(): void {
console.log("Connecting to PostgreSQL database");
}
disconnect(): void {
console.log("Disconnecting from PostgreSQL");
}
}
class PostgreSQLQuery implements Query {
execute(sql: string): void {
console.log(`Executing PostgreSQL query: ${sql}`);
}
}
class PostgreSQLResult implements Result {
fetch(): any[] {
return [{ id: 1, name: "PostgreSQL Data" }];
}
}
// Abstract Factory
interface DatabaseFactory {
createConnection(): Connection;
createQuery(): Query;
createResult(): Result;
}
// Concrete Factories
class MySQLFactory implements DatabaseFactory {
createConnection(): Connection {
return new MySQLConnection();
}
createQuery(): Query {
return new MySQLQuery();
}
createResult(): Result {
return new MySQLResult();
}
}
class PostgreSQLFactory implements DatabaseFactory {
createConnection(): Connection {
return new PostgreSQLConnection();
}
createQuery(): Query {
return new PostgreSQLQuery();
}
createResult(): Result {
return new PostgreSQLResult();
}
}
// Client
class DatabaseService {
private connection: Connection;
private query: Query;
constructor(factory: DatabaseFactory) {
this.connection = factory.createConnection();
this.query = factory.createQuery();
}
executeQuery(sql: string): void {
this.connection.connect();
this.query.execute(sql);
this.connection.disconnect();
}
}
// Usage
const dbType = process.env.DB_TYPE || "mysql";
const factory = dbType === "mysql"
? new MySQLFactory()
: new PostgreSQLFactory();
const dbService = new DatabaseService(factory);
dbService.executeQuery("SELECT * FROM users");

  1. Identify Product Families Determine related products that should be created together.
  2. Define Abstract Products Create interfaces for each product type in the family.
  3. Implement Concrete Products Create specific implementations for each family variant.
  4. Create Abstract Factory Define an interface with creation methods for each product.
  5. Implement Concrete Factories Create a factory for each product family variant.
  6. Update Client Code Ensure clients work with abstract interfaces only.

Ensure Compatibility

All products from a factory must be compatible with each other.

Use Dependency Injection

Pass factories to clients through constructors or parameters.

Keep Families Cohesive

Products in a family should have a strong relationship.

Document Families

Clearly document which products belong to which family.



Abstract FactoryFactory Method
Creates families of related objectsCreates one type of object
Uses compositionUses inheritance
Factory is an objectFactory is a method
Multiple product typesSingle product type

  • When your code needs to work with various families of related products
  • When you want to enforce constraints on product combinations
  • When you want to provide a library of products revealing only interfaces
  • When product families need to be independent

  • When you only have one product family
  • When product creation is simple
  • When flexibility to add new product types is important
  • When the added complexity doesn’t provide value