1. Одноэлементный шаблон

class Singleton {
  constructor() {
    if (Singleton.instance) {
      return Singleton.instance;
    }
    Singleton.instance = this;
  }
  getInstance() {
    return Singleton.instance;
  }
}
const singleton1 = new Singleton();
const singleton2 = new Singleton();
console.log(singleton1 === singleton2); // true

В этом примере класс Singleton имеет конструктор, который проверяет, существует ли уже экземпляр класса. Если это так, конструктор возвращает этот существующий экземпляр вместо создания нового. Метод getInstance используется для доступа к экземпляру singleton. При создании нескольких экземпляров класса все они будут ссылаться на один и тот же объект в памяти, гарантируя, что существует только один экземпляр класса.

2. Шаблон фабричного метода

Шаблон Factory Method — это порождающий шаблон проектирования, который предоставляет интерфейс для создания объектов в суперклассе, но позволяет подклассам изменять тип создаваемых объектов. Вот пример шаблона Factory Method, реализованного в JavaScript:

class Creator {
    factoryMethod() {
        throw new Error("This method must be overridden!");
    }    
    someOperation() {
        const product = this.factoryMethod();
        return `Creator: The same creator's code has just worked with ${product.operation()}`;
    }
}
class ConcreteCreatorA extends Creator {
    factoryMethod() {
        return new ConcreteProductA();
    }
}
class ConcreteCreatorB extends Creator {
    factoryMethod() {
        return new ConcreteProductB();
    }
}
class Product {
    operation() {
        throw new Error("This method must be overridden!");
    }
}
class ConcreteProductA extends Product {
    operation() {
        return "ConcreteProductA";
    }
}
class ConcreteProductB extends Product {
    operation() {
        return "ConcreteProductB";
    }
}
const creatorA = new ConcreteCreatorA();
console.log(creatorA.someOperation()); // Creator: The same creator's code has just worked with ConcreteProductA
const creatorB = new ConcreteCreatorB();
console.log(creatorB.someOperation()); // Creator: The same creator's code has just worked with ConcreteProductB

В этом примере у нас есть класс Creator, который определяет фабричный метод factoryMethod, который переопределяется в классах ConcreteCreatorA и ConcreteCreatorB. Классы ConcreteCreatorA и ConcreteCreatorB создают разные типы продуктов, ConcreteProductA и ConcreteProductB соответственно. Метод someOperation в классе Creator использует фабричный метод для создания продукта, а метод operation вызывается для возвращаемого продукта.

3. Абстрактный заводской узор

Шаблон «Абстрактная фабрика» — это порождающий шаблон проектирования, предоставляющий интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов. Вот пример шаблона абстрактной фабрики, реализованного в JavaScript:

class AbstractFactory {
    createProductA() {
        throw new Error("This method must be overridden!");
    }    
    createProductB() {
        throw new Error("This method must be overridden!");
    }
}
class ConcreteFactory1 extends AbstractFactory {
    createProductA() {
        return new ConcreteProductA1();
    }
    createProductB() {
        return new ConcreteProductB1();
    }
}
class ConcreteFactory2 extends AbstractFactory {
    createProductA() {
        return new ConcreteProductA2();
    }
    createProductB() {
        return new ConcreteProductB2();
    }
}
class AbstractProductA {
    operationA() {
        throw new Error("This method must be overridden!");
    }
}
class AbstractProductB {
    operationB() {
        throw new Error("This method must be overridden!");
    }
}
class ConcreteProductA1 extends AbstractProductA {
    operationA() {
        return "ConcreteProductA1";
    }
}
class ConcreteProductA2 extends AbstractProductA {
    operationA() {
        return "ConcreteProductA2";
    }
}
class ConcreteProductB1 extends AbstractProductB {
    operationB() {
        return "ConcreteProductB1";
    }
}
class ConcreteProductB2 extends AbstractProductB {
    operationB() {
        return "ConcreteProductB2";
    }
}
const factory1 = new ConcreteFactory1();
const productA1 = factory1.createProductA();
const productB1 = factory1.createProductB();
console.log(productA1.operationA()); // ConcreteProductA1
console.log(productB1.operationB()); // ConcreteProductB1
const factory2 = new ConcreteFactory2();
const productA2 = factory2.createProductA();
const productB2 = factory2.createProductB();
console.log(productA2.operationA()); // ConcreteProductA2
console.log(productB2.operationB()); // ConcreteProductB2

В этом примере у нас есть класс AbstractFactory, определяющий методы создания продуктов, createProductA и createProductB, которые переопределяются в классах ConcreteFactory1 и ConcreteFactory2. Классы ConcreteFactory1 и ConcreteFactory2 создают разные типы продуктов, ConcreteProductA1, ConcreteProductB1, ConcreteProductA2 и ConcreteProductB2 соответственно. Методы operationA и operationB вызываются для возвращаемых продуктов. Клиентский код может работать с любой конкретной фабрикой и ее продуктами, не зная их классов.

4. Шаблон построителя

Шаблон Builder — это творческий шаблон проектирования, который позволяет поэтапно создавать сложные объекты с использованием определенного типа стандартного блока в определенном порядке. Вот пример шаблона Builder, реализованного в JavaScript:

class Builder {
    buildPartA() {
        throw new Error("This method must be overridden!");
    }
    buildPartB() {
        throw new Error("This method must be overridden!");
    }
    buildPartC() {
        throw new Error("This method must be overridden!");
    }
    getResult() {
        throw new Error("This method must be overridden!");
    }
}
class ConcreteBuilder1 extends Builder {
    constructor() {
        super();
        this.product = new Product1();
    }
    buildPartA() {
        this.product.parts.push("PartA1");
    }
    buildPartB() {
        this.product.parts.push("PartB1");
    }
    buildPartC() {
        this.product.parts.push("PartC1");
    }
    getResult() {
        return this.product;
    }
}
class ConcreteBuilder2 extends Builder {
    constructor() {
        super();
        this.product = new Product2();
    }
    buildPartA() {
        this.product.parts.push("PartA2");
    }
    buildPartB() {
        this.product.parts.push("PartB2");
    }
    buildPartC() {
        this.product.parts.push("PartC2");
    }
    getResult() {
        return this.product;
    }
}
class Product {
    constructor() {
        this.parts = [];
    }
}
class Product1 extends Product {
    parts(){
        return this.parts;
    }
}
class Product2 extends Product {
    parts(){
        return this.parts;
    }
}
const director = new Director();
const builder1 = new ConcreteBuilder1();
director.build(builder1);
const product1 = builder1.getResult();
console.log(product1.parts); // ["PartA1", "PartB1", "PartC1"]
const builder2 = new ConcreteBuilder2();
director.build(builder2);
const product2 = builder2.getResult();
console.log(product2.parts); // ["PartA2", "PartB2", "PartC2"]

В этом примере у нас есть класс Builder, определяющий методы построения частей продукта, buildPartA, buildPartB и buildPartC, которые переопределяются в классах ConcreteBuilder1 и ConcreteBuilder2. Классы ConcreteBuilder1 и ConcreteBuilder2 создают разные типы продуктов, Product1 и Product2 соответственно. Метод getResult используется для получения конечного продукта. Класс Director отвечает за процесс построения, он использует конструктор для сборки конечного продукта. В этом примере класс директора не реализован, но вы можете реализовать его, добавив метод сборки и используя его в клиентском коде.

5. Образец прототипа

Шаблон прототипа — это творческий шаблон проектирования, который позволяет создавать новые объекты путем копирования существующих, а не создавать новые объекты с нуля. Вот пример шаблона Prototype, реализованного в JavaScript:

class Prototype {
    constructor() {
        this.primitive = null;
        this.component = null;
        this.circularReference = null;
    }
    clone() {
        const clone = Object.create(this);
        clone.component = Object.create(this.component);
        clone.circularReference = {
            ...this.circularReference,
            prototype: {...this}
        };
        return clone;
    }
}
class ComponentWithBackReference {
    constructor(prototype) {
        this.prototype = prototype;
    }
}
const prototype = new Prototype();
prototype.primitive = 245;
prototype.component = new Date();
prototype.circularReference = new ComponentWithBackReference(prototype);
const clone = prototype.clone();
console.log(clone.primitive); // 245
console.log(clone.component); // Mon Jan 24 2022 10:22:56 GMT-0800 (Pacific Standard Time)
console.log(clone.circularReference.prototype === prototype); // true
console.log(prototype.circularReference.prototype === prototype); // true

В этом примере класс Prototype имеет метод clone, который создает новый объект с теми же свойствами, что и исходный объект. Метод Object.create используется для создания нового объекта с тем же прототипом, что и исходный объект, а затем копируются свойства. В этом примере метод клонирования использует object.create для клонирования поля компонента и оператор распространения для клонирования поля circleReference. Класс ComponentWithBackReference используется для демонстрации того, что свойства нового объекта не зависят от свойств исходного объекта, даже если они содержат ссылки на исходный объект.

Обратите внимание, что этот пример является простым примером для иллюстрации концепции шаблона прототипа. В реальных сценариях вам может потребоваться использовать дополнительные библиотеки, такие как lodash или Ramda, для глубокого клонирования объекта.