Creational Design Pattern
Creational design patterns focus on object creation mechanisms, trying to create objects in a manner suitable to the situation. The basic form of object creation could result in design problems or added complexity to the design. Creational design patterns solve this problem by controlling the object creation process. Here's a brief overview of some common creational design patterns:
Singleton Pattern: Ensures a class has only one instance and provides a global point of access to it. Useful when only one instance of a class is needed across the system.
class Singleton {
private static instance: Singleton;
private constructor() {}
public static getInstance(): Singleton {
if (!Singleton.instance) {
Singleton.instance = new Singleton();
}
return Singleton.instance;
}
}
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // Output: true
- Factory Method Pattern: Defines an interface for creating an object, but let subclasses decide which class to instantiate. It provides a way to delegate the instantiation logic to child classes.
interface Product {
operation(): string;
}
class ConcreteProduct1 implements Product {
operation(): string {
return 'Product 1';
}
}
class ConcreteProduct2 implements Product {
operation(): string {
return 'Product 2';
}
}
abstract class Creator {
public abstract factoryMethod(): Product;
public someOperation(): string {
const product = this.factoryMethod();
return `Creator: ${product.operation()}`;
}
}
class ConcreteCreator1 extends Creator {
public factoryMethod(): Product {
return new ConcreteProduct1();
}
}
class ConcreteCreator2 extends Creator {
public factoryMethod(): Product {
return new ConcreteProduct2();
}
}
const creator1 = new ConcreteCreator1();
console.log(creator1.someOperation()); // Output: "Creator: Product 1"
const creator2 = new ConcreteCreator2();
console.log(creator2.someOperation()); // Output: "Creator: Product 2"
Factory Pattern: Provides an interface for creating families of related or dependent objects without specifying their concrete classes. It's like a factory of factories.
interface AbstractFactory {
createProductA(): AbstractProductA;
createProductB(): AbstractProductB;
}
interface AbstractProductA {
usefulFunctionA(): string;
}
interface AbstractProductB {
usefulFunctionB(): string;
}
class ConcreteFactory1 implements AbstractFactory {
createProductA(): AbstractProductA {
return new ConcreteProductA1();
}
createProductB(): AbstractProductB {
return new ConcreteProductB1();
}
}
class ConcreteFactory2 implements AbstractFactory {
createProductA(): AbstractProductA {
return new ConcreteProductA2();
}
createProductB(): AbstractProductB {
return new ConcreteProductB2();
}
}
class ConcreteProductA1 implements AbstractProductA {
usefulFunctionA(): string {
return 'The result of the product A1.';
}
}
class ConcreteProductB1 implements AbstractProductB {
usefulFunctionB(): string {
return 'The result of the product B1.';
}
}
class ConcreteProductA2 implements AbstractProductA {
usefulFunctionA(): string {
return 'The result of the product A2.';
}
}
class ConcreteProductB2 implements AbstractProductB {
usefulFunctionB(): string {
return 'The result of the product B2.';
}
}
function clientCode(factory: AbstractFactory) {
const productA = factory.createProductA();
const productB = factory.createProductB();
console.log(productA.usefulFunctionA());
console.log(productB.usefulFunctionB());
}
const factory1 = new ConcreteFactory1();
clientCode(factory1);
const factory2 = new ConcreteFactory2();
clientCode(factory2);
Builder Pattern: Separate the construction of a complex object from its representation, allowing the same construction process to create various representations.
class Product {
private parts: string[] = [];
public addPart(part: string): void {
this.parts.push(part);
}
public listParts(): void {
console.log(`Product parts: ${this.parts.join(', ')}`);
}
}
interface Builder {
buildPartA(): void;
buildPartB(): void;
buildPartC(): void;
getResult(): Product;
}
class ConcreteBuilder implements Builder {
private product: Product = new Product();
public buildPartA(): void {
this.product.addPart('Part A');
}
public buildPartB(): void {
this.product.addPart('Part B');
}
public buildPartC(): void {
this.product.addPart('Part C');
}
public getResult(): Product {
return this.product;
}
}
class Director {
private builder: Builder;
constructor(builder: Builder) {
this.builder = builder;
}
public construct(): void {
this.builder.buildPartA();
this.builder.buildPartB();
this.builder.buildPartC();
}
}
const builder = new ConcreteBuilder();
const director = new Director(builder);
director.construct();
const product = builder.getResult();
product.listParts();