Skip to content

shuaibird/design-patterns-diagram

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OOP Design Patterns

Overview

A curated list of common OOP design patterns.

This README.md is generated by running yarn start.

Categories

Behavioral

Behavioral patterns are algorithms and the assignment of responsibilities between objects.

Creational

Creational patterns provide various object creation mechanisms, which increase flexibility and reuse of existing code.

Structural

Structural patterns explain how to assemble objects and classes into larger structures, while keeping this structures flexible and efficient.

Table of Contents

Patterns

Behavioral - Chain Of Responsibility

back to top

Behavioral - Chain Of Responsibility

abstract class Middleware {
    protected next: Middleware | null = null;

    public setNext(next: Middleware): void {
        this.next = next;
    }

    public abstract run(request: Record<string, boolean>): void;
}

class Authentication extends Middleware {
    public run(request: Record<string, boolean>): void {
        if (request.isAuthenticated) {
            this.next && this.next.run(request);
            return;
        }
        console.log(401);
    }
}

class Authorization extends Middleware {
    public run(request: Record<string, boolean>): void {
        if (request.isAdmin) {
            this.next && this.next.run(request);
            return;
        }
        console.log(403);
    }
}

const authentication = new Authentication();
const authorization = new Authorization();
authentication.setNext(authorization);

// middlewares stack
const middlewares = authentication;
middlewares.run({ isAuthenticated: true, isAdmin: false }); // 403

Behavioral - Command

back to top

Behavioral - Command

interface Command {
    execute(): void;
}

class ConcreteCommand implements Command {
    #receiver: Receiver;
    constructor(receiver: Receiver) {
        this.#receiver = receiver;
    }
    public execute(): void {
        this.#receiver.onReceive();
    }
}

class Sender {
    public execute(command: Command): void {
        command.execute();
    }
}

class Receiver {
    public onReceive(): void {}
}

Behavioral - Iterator

back to top

Behavioral - Iterator

interface IIterator<T> {
    next(): T;
    hasNext(): boolean;
}

interface IIterable<T> {
    iterator(): IIterator<T>;
}

class ConcreteIterator<T> implements IIterator<T> {
    next(): T {}
    hasNext(): boolean {}
}

class ConcreteIterable<T> implements IIterable<T> {
    public iterator(): IIterator<T> {
        return new ConcreteIterator();
    }
}

Behavioral - Mediator

back to top

Behavioral - Mediator

interface Mediator {
    notify(component: Component): void;
}

abstract class Component {
    protected mediator: Mediator;
    constructor(mediator: Mediator) {
        this.mediator = mediator;
    }
    public abstract operate(): void;
}

class ConcreteMediator implements Mediator {
    public notify(component: Component): void {}
}

class ConcreteComponent extends Component {
    public operate(): void {
        this.mediator.notify(this);
    }
}

Creational - Builder

back to top

Creational - Builder

class Product {
    #required: any;
    public optionalA: any;
    public optionalB: any;
    public constructor(required: any) {
        this.#required = required;
    }
}

class Builder {
    #product: Product;
    public constructor(required: any) {
        this.#product = new Product(required);
    }
    public setOptionalA(optionalA: any): Builder {
        this.#product.optionalA = optionalA;
        return this;
    }
    public setOptionalB(optionalB: any): Builder {
        this.#product.optionalB = optionalB;
        return this;
    }
    public build(): Product {
        return this.#product;
    }
}

const product = new Builder("required")
    .setOptionalA("optionalA")
    .setOptionalB("optionalB")
    .build();

Creational - Factory - Abstract Factory

back to top

Creational - Factory - Abstract Factory

interface Component1 {}
class Component1A implements Component1 {}
class Component1B implements Component1 {}
interface Component2 {}
class Component2A implements Component2 {}
class Component2B implements Component2 {}

abstract class FactoryBase {
    public assemble(): void {
        const comp1 = this.createComponent1();
        const comp2 = this.createComponent2();
    }
    protected abstract createComponent1(): Component1;
    protected abstract createComponent2(): Component2;
}

class FactoryA extends FactoryBase {
    protected createComponent1(): Component1 {
        return new Component1A();
    }
    protected createComponent2(): Component2 {
        return new Component2A();
    }
}

class FactoryB extends FactoryBase {
    protected createComponent1(): Component1 {
        return new Component1B();
    }
    protected createComponent2(): Component2 {
        return new Component2B();
    }
}

Creational - Factory - Factory Method

back to top

Creational - Factory - Factory Method

interface Product {}
class ProductA implements Product {}
class ProductB implements Product {}

abstract class FactoryBase {
    public abstract createProduct(): Product;
}

class FactoryA extends FactoryBase {
    public createProduct(): Product {
        return new ProductA();
    }
}

class FactoryB extends FactoryBase {
    public createProduct(): Product {
        return new ProductB();
    }
}

Creational - Factory - Simple Factory

back to top

Creational - Factory - Simple Factory

interface Product {}
class ProductA implements Product {}
class ProductB implements Product {}

class Factory {
    public static createProduct(type: string): Product {
        switch (type) {
            case "A":
                return new ProductA();
            case "B":
                return new ProductB();
            default:
        }
    }
}

Creational - Prototype

back to top

Creational - Prototype

interface Prototype<T> {
    clone(): T;
}

class Product implements Prototype<Product> {
    public field: any;

    public constructor();
    public constructor(product: Product);
    public constructor(product?: Product) {
        if (product) {
            this.field = product.field;
        }
    }

    clone(): Product {
        return new Product(this);
    }
}

Creational - Singleton

back to top

Creational - Singleton

class Singleton {
    private static instance: Singleton;
    private constructor() {}

    public static getInstance(): Singleton {
        if (!Singleton.instance) {
            Singleton.instance = new Singleton();
        }
        return Singleton.instance;
    }
}

new Singleton(); //impossible
Singleton.getInstance() == Singleton.getInstance(); //true

Structural - Adapter

back to top

Structural - Adapter

interface X {}
interface Y {}
interface Z {}

class Client {
    public userService(data: X): Z {
        return new Adapter(new Service()).run(data);
    }
}

class Adapter {
    #service: Service;
    public constructor(service: Service) {
        this.#service = service;
    }
    public run(data: X): Z {
        return this.#service.run(data);
    }
}

class Service {
    public run(data: Y): Z {}
}

Structural - Bridge

back to top

Structural - Bridge

abstract class Shape {
    #color: Color;
    public constructor(color: Color) {
        this.#color = color;
    }
    public getColor(): void {
        this.#color.getColor();
    }
    public abstract getShape(): void;
}

abstract class Color {
    public abstract getColor(): void;
}

class Circle extends Shape {
    public getShape(): void {
        console.log("circle");
    }
}

class Blue extends Color {
    public getColor(): void {
        console.log("blue");
    }
}

const blueCircle = new Circle(new Blue());
blueCircle.getShape(); // circle
blueCircle.getColor(); // blue

Structural - Composite

back to top

Structural - Composite

interface Component {
    execute(): void;
}

class Container implements Component {
    #comps: Component[] = [];
    public add(comp: Component) {
        this.#comps.push(comp);
    }
    public execute(): void {
        for (const comp of this.#comps) {
            comp.execute();
        }
    }
}

class Leaf implements Component {
    public execute(): void {}
}

Structural - Decorator

back to top

Structural - Decorator

interface Component {
    execute(): void;
}

class ConcreteComponent implements Component {
    public execute(): void {
        console.log("from ConcreteComponent");
    }
}

abstract class BaseDecorator implements Component {
    #comp: Component;
    public constructor(comp: Component) {
        this.#comp = comp;
    }

    execute(): void {
        this.#comp.execute();
    }
}

class ConcreteDecoratorA extends BaseDecorator {
    public execute(): void {
        super.execute();
        this.extra();
    }

    private extra(): void {
        console.log("from ConcreteDecoratorA");
    }
}

class ConcreteDecoratorB extends BaseDecorator {
    public execute(): void {
        super.execute();
        this.extra();
    }

    private extra(): void {
        console.log("from ConcreteDecoratorB");
    }
}

const comp = new ConcreteComponent();
comp.execute();
const decoratedCompA = new ConcreteDecoratorA(comp);
decoratedCompA.execute();
const decoratedCompB = new ConcreteDecoratorB(decoratedCompA);
decoratedCompB.execute();

Structural - Facade

back to top

Structural - Facade

class ComponentA {
    public static process() {}
}

class ComponentB {
    public static process() {}
}

class Facade {
    public static process() {
        ComponentA.process();
        ComponentB.process();
    }
}

Facade.process();

Structural - Flyweight

back to top

Structural - Flyweight

class Forest {
    #trees: Tree[];
    #factory = new TreeTypeFactory();

    plantTree({
        x,
        y,
        name,
        color,
        texture,
    }: {
        x: number;
        y: number;
        name: string;
        color: string;
        texture: string;
    }): void {
        this.#trees.push(
            new Tree(this.#factory, { x, y, name, color, texture })
        );
    }
}

class Tree {
    public x: number;
    public y: number;
    public type: TreeType;

    public constructor(
        factory: TreeTypeFactory,
        {
            x,
            y,
            name,
            color,
            texture,
        }: {
            x: number;
            y: number;
            name: string;
            color: string;
            texture: string;
        }
    ) {
        this.x = x;
        this.y = y;
        // instead of directly constructing a new treeType
        // fetch the treeType from factory
        // to save memory usage
        this.type = factory.getTreeType({ name, color, texture });
    }
}

class TreeTypeFactory {
    #cache: Record<string, TreeType>;
    public getTreeType({
        name,
        color,
        texture,
    }: {
        name: string;
        color: string;
        texture: string;
    }): TreeType {
        const key = this.hashKey({ name, color, texture });
        if (!this.#cache[key]) {
            this.#cache[key] = new TreeType({ name, color, texture });
        }
        return this.#cache[key];
    }

    private hashKey({
        name,
        color,
        texture,
    }: {
        name: string;
        color: string;
        texture: string;
    }): string {
        return `${name}-${color}-${texture}`;
    }
}

class TreeType {
    #name: string;
    #color: string;
    #texture: string;

    public constructor({
        name,
        color,
        texture,
    }: {
        name: string;
        color: string;
        texture: string;
    }) {
        this.#name = name;
        this.#color = color;
        this.#texture = texture;
    }
}

Structural - Proxy

back to top

Structural - Proxy

interface IDownloader {
    download(query: string): string;
}

class Downloader implements IDownloader {
    public download(query: string): string {
        return query;
    }
}

class DownloaderProxy implements IDownloader {
    #downloader: Downloader;
    #cache: Record<string, string>;

    public constructor(downloader: Downloader) {
        this.#downloader = downloader;
    }
    public download(query: string): string {
        if (!this.#cache[query]) {
            this.#cache[query] = this.#downloader.download(query);
        }
        return this.#cache[query];
    }
}

const downloaderWithCache = new DownloaderProxy(new Downloader());

References

About

Design patterns diagram

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published