kdocs
GitHub
SC - Software Architecture
SC - Software Architecture
  • About
    • Architectural Requirements (RAs)
    • Architectural Perspectives
  • Software Design
    • Microservices
      • Patterns
    • Monolithic
    • C4 Model
  • Software Architectures
    • Clean Architecture
    • DDD (Domain Driven Design)
      • Strategic Modeling
      • Tactical Modeling
    • Event Driven Architecture
      • CAP Theorem
    • Hexagonal Architecture (Ports and Adapters)
  • Design Patterns
    • Behavioral
    • Creational
    • Data Access
    • Structural
  • Practices
    • Clean Code
    • SOLID
  • Others
    • CQRS
Powered by GitBook
On this page
  • Factory Method
  • Abstract Factory
  • Builder
  • Prototype
  • Singleton
  1. Design Patterns

Creational

How objects are created.

PreviousBehavioralNextData Access

Last updated 4 months ago

It provides an interface for creating specialized objects of a superclass, and allowing that each subclass decides which instance to create.

The superclass will only have the creation abstract method. The implementation of the creation method will be inside each subclass.

Factory Method pattern suggests that you replace direct object construction calls (using the new operator) with calls to a special factory method (like create()).

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

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.

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.

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.

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

Chair.ts
interface Chair {
    color: string;
    price(): number;
}

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

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

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.

Factory.ts
interface ChairFactory {
    createChair(): Chair;
}

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

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

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

The distinct Factory will then be injected.

Usecase1.ts
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();
    }
}

  • Used for instantiating a class step-by-step with methods instead of passing everything to the constructor only once.

  • An alternative way to implement inheritance.

    • But instead of inherit from a class, it does from an object that has been already created.

  • In Javascript this is built-in with the prototypes from objects.

Used when you want to maintain only one instance of something in the application. (Like DB instance, socket, etc)

It does this by making the constructor private, so that only ONE static method (like getInstance()) from the class can call it, ONLY ONCE to instantiate it.

This helps so that you do not need to pass these classes by parameters to dependency inject them.

It can become an anti-pattern in data-shared environments with multi thread, since it won't be clear who should be mutating the state.

Ex.: It can lead to race conditions.

To avoid multiple threads trying to create at the same time an instance, you must use a lock and recheck the instance === null inside the lock.

class MyClass {
    private someProp: any;
    static instance: MyClass;
    
    private constructor (){}
    
    doSomething() {
        return this.someProp;
    }
    
    static getIntance() {
        if (!MyClass.intance) MyClass.instance = new MyClass();
        return MyClass.instance;
    }
}

On the outside you just call the getInstance() before using the Class.

Abstract Factory
Builder
Prototype
Singleton
Factory Method
The Catalog of Design Patterns
Logo