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

Итак, что такое шаблоны проектирования 😃?

Проще говоря, шаблоны проектирования — это многоразовые решения часто встречающихся проблем при проектировании программного обеспечения. Шаблоны проектирования используются для представления некоторых лучших практик, адаптированных опытными разработчиками объектно-ориентированного программного обеспечения. Шаблон проектирования систематически называет, мотивирует и объясняет общий проект, который решает повторяющуюся проблему проектирования в объектно-ориентированных системах. Он описывает проблему, решение, когда применять решение и его последствия. В нем также приводятся советы по реализации и примеры.
Еще один способ рассматривать шаблоны — это шаблоны того, как мы решаем проблемы, которые можно использовать в самых разных ситуациях.

Одним из наиболее важных аспектов написания поддерживаемого кода является возможность замечать повторяющиеся темы в этом коде и оптимизировать их. Это та область, где знание шаблонов проектирования может оказаться бесценным.
Основные преимущества, которые мы получаем от шаблонов проектирования, заключаются в следующем:
1. Это проверенные решения.
2. Их легко использовать повторно. .
3. Они выразительны.
4. Они облегчают общение, чтобы сделать ваш код более понятным другим разработчикам.
5. Они уменьшают размер базы кода.
6. Они предотвращают необходимость рефакторинга кода.

В этой статье мы увидим, как некоторые из наиболее важных шаблонов проектирования применимы к Node.js и его философии, тем самым заново открыв для себя их важность с другой точки зрения.
В этой статье рассматриваются следующие шаблоны проектирования:

  • Factory Pattern
    -Singleton Pattern
    -Observer Pattern
    -Proxy Pattern
    -Strategy Pattern

Веселитесь 😉? …

1. Фабричный шаблон. Фабричный шаблон отделяет создание объекта от его реализации. Таким образом, это дает нам больше свободы и контроля над тем, как мы это делаем, а это означает, что мы можем использовать весь набор инструментов для создания новых объектов — литералы объектов, конструкторы, Object.Create(), замыкания, прототипы, статические поля — но все это будет скрыто от пользователя нашей фабричной функции.

Когда использовать
Шаблон Factory полезен в следующих ситуациях:
- Нам нужно создавать новые разные объекты в зависимости от необходимости
- Мы хотим принудительно инкапсулировать

Предположим, вы пытаетесь создать веб-приложение для управления сотрудниками. В компании есть разные сотрудники. Пока предположим, что в компании работают три типа сотрудников.

Инженер
Менеджер

Итак, давайте создадим отдельный класс для обработки каждого типа сотрудников.
Вот класс Engineer:

/* инженер.js */

class Engineer{
конструктор(fName, lName){
this.firstName = fName
this.lastName = lName
}

getName(){
return ‘ Engineer ‘ + this.firstName + “ “ + this.lastName
}
}
module.exports = Engineer

Вот класс Manager:
/* manager.js */

class Manager{
конструктор(fname, lname){
this.firstName = fname
this.lastName = lname
}

getName(){
return 'Менеджер' + this.firstName + " " + this.lastName
}
}
module.exports = Manager

Вы будете использовать вышеуказанные классы в файле приложения и создавать объекты. Создайте файл с именем index.js. Этот файл будет файлом нашего приложения. Вы создадите новый экземпляр каждого типа сотрудников и отобразите их имена. Вот как выглядит файл index.js:

const Engineer = require('./engineer')
const Manager = require('./manager')

let инженер = новый инженер('Рой', 'Агастьян')
пусть менеджер = новый менеджер('Сэм', 'Джонсон')

console.log('Инженер есть', engineering.getName())
console.log('Менеджер есть', manager.getName())

Сохраните вышеуказанные изменения и попробуйте запустить файл index.js. Все выглядит хорошо и должно работать нормально.

Проблема возникнет, когда приложение разрастется и, скажем, добавится еще несколько новых типов сотрудников. Наш файл index.js должен будет импортировать все новые типы сотрудников и создавать экземпляры каждого из них.

Решение: шаблон проектирования фабрик в Node.js
Вы можете использовать шаблон проектирования фабрик в Node.js, чтобы упростить свой код и уменьшить его беспорядочность. Вам нужно создать фабрику, которая будет импортировать разные классы сотрудников. Вместо того, чтобы импортировать все типы сотрудников в index.js, вы можете импортировать фабрику.

Давайте посмотрим, как вы можете это реализовать. Создайте файл с именем empFactory.js. Внутри empFactory.js импортируйте все необходимые классы сотрудников. В зависимости от типа сотрудника вы можете вернуть разные экземпляры сотрудников в код приложения. Вот как это выглядит:

/* empFactory.js */

const Engineer = require('./engineer')
const Manager = require('./manager')

const empFactory = function(fname, lname, type){
if(type === 'engineer'){
return new Engineer(fname,lname)
} else if(type == = 'manager') {
return new Manager(fname, lname)
} else {
throw new Error('БД не поддерживается');
}
}

модуль.экспорт = empFactory

Теперь измените код index.js для импорта из empFactory.js и создайте экземпляр на основе типа сотрудника. Вот как выглядит файл index.js:

/* index.js */

const empFactory = требуется('./empFactory')

пусть инженер = empFactory('Рой','Агастьян','инженер')
пусть менеджер = empFactory('Сэм','Джонсон','менеджер')

console.log(engineer.getName())
console.log(manager.getName())

Подробнее можно узнать здесь

2. Одноэлементный шаблон. Одноэлементные шаблоны ограничивают количество экземпляров «класса» до одного. Создавать синглтоны в Node.js довольно просто, так как require поможет вам. Шаблон singleton используется в сценариях, когда нам нужен ровно один экземпляр класса. Например, нам нужен объект, который содержит некоторую конфигурацию для чего-то. В этих случаях нет необходимости создавать новый объект всякий раз, когда объект конфигурации требуется где-то в системе. В основном, одноэлементный шаблон позволяет вам создать экземпляр объекта один раз, а затем использовать его каждый раз, когда он вам нужен, вместо создания нового без необходимости отслеживать ссылку на него, либо глобально, либо просто передавая его как зависимость везде. Вы также можете получить синглтон, просто экспортировав новый экземпляр класса из файла.

Примечание: есть сценарии, когда синглтоны могут быть плохими, и аргументы в пользу того, что они, по сути, всегда плохие. Для этого обсуждения вы можете проверить эту полезную статью. Скажем, вы хотите иметь синглтон класса БД, в вашем db/index.js у вас будет следующее:

class Database {
статическое соединение;
/* … */
}

экспортировать новую базу данных по умолчанию (dbConfig);

И теперь вы можете импортировать это в несколько файлов, и вы получите один и тот же экземпляр.
Это возможно благодаря тому, что модули спроектированы для работы в node. Короче говоря, модули кэшируются 😅.

//area.js
var PI = Math.PI;

функция круг (радиус) {
возвращает радиус * радиус * PI;
}

модуль.экспорт.круг = круг;

Неважно, сколько раз вам потребуется этот модуль в вашем приложении; он будет существовать только как единственный экземпляр.

var areaCalc = требуется('./площадь');

console.log(areaCalc.circle(5));

Из-за такого поведения require синглтоны, вероятно, являются наиболее распространенными шаблонами проектирования Node.js среди модулей в NPM.

Подробнее можно узнать здесь 🔍.

3. Шаблон Observer: Во многих случаях, когда одна часть приложения изменяется, необходимо обновить другие части. Шаблон наблюдателя используется как способ уведомления об изменении ряда классов. Этот паттерн очень интересен в том смысле, что он позволяет вам реагировать на определенные входные данные, реагируя на них, вместо того, чтобы заранее проверять, предоставлены ли входные данные. Другими словами, с помощью этого шаблона вы можете указать, какой тип ввода вы ожидаете, и пассивно ждать, пока этот ввод не будет предоставлен, чтобы выполнить ваш код. Если хотите, это сделка типа «поставь и забудь». Все, что связано с событиями в Nodejs, реализует этот шаблон. Объект поддерживает список иждивенцев/наблюдателей и автоматически уведомляет их об изменениях состояния. Для реализации паттерна наблюдателя на помощь приходит EventEmitter.

Общий вид шаблона Observer выглядит следующим образом:

EventObserver

├── подписка: добавляет новые наблюдаемые события

├── отписка: удаляет наблюдаемые события
|
└── широковещательная рассылка: выполняет все события со связанными данными

Прекрасный пример шаблона Observer, прямо из коробки. И вы можете расширить EventEmitter Node, чтобы делать все, что захотите:

const EventEmitter = require('events').EventEmitter;

class PingPing extends EventEmitter {
конструктор() {
super();
this.on(' ping', this.pong);
}

ping() {
console.log('ping');
this.emit('ping') ;
}

pong() {
console.log('pong');
}
}

const pingPong = new PingPing();
pingPong.ping();
// ping в качестве вывода
// pong в качестве вывода

4. Шаблон прокси-сервера. Прокси-сервер представляет собой заполнитель для другого объекта для управления доступом, снижения затрат и упрощения. Прокси — это объект, который контролирует доступ к другому объекту, называемому субъектом. Прокси и субъект имеют идентичный интерфейс и это позволяет нам прозрачно менять местами одно на другое; на самом деле, альтернативное название этого шаблона — суррогат. Прокси перехватывает все или некоторые операции, предназначенные для выполнения над субъектом, увеличивая или дополняя их поведение. На следующем рисунке показано схематическое представление:

На предыдущем рисунке показано, как прокси и субъект имеют один и тот же интерфейс и как он полностью прозрачен для клиента, который может использовать один или другой взаимозаменяемо. Прокси перенаправляет каждую операцию субъекту, улучшая его поведение с помощью дополнительной предварительной или последующей обработки.

Примечание. Важно отметить, что мы не говорим о проксировании между классами; Паттерн Proxy включает в себя обертывание реальных экземпляров субъекта, сохраняя таким образом его состояние. Прокси-сервер полезен в нескольких случаях, при проверке данных, безопасности, кэшировании, ведении журнала и т. д. Этот шаблон проектирования должен быть относительно простым и понятным, поэтому давайте рассмотрим пример. Комментарии в коде объясняют предполагаемую функциональность каждого метода.

let BankAccounts = function() {
//конструктор
};

BankAccounts.prototype = {
add(bankAccountData) {
// функционал добавления нового банковского счета
},
find(bankAccount) {
// поиск список банковских счетов
},
getList() {
// возвращает список всех банковских счетов
}
};

// создание прокси
var BankAccountsProxy = function() {
// получение ссылки на исходный объект
this.bankAccounts = new BankAccounts();
};

BankAccountsProxy.prototype = {
addBankAccount(bankAccountData) {
// некоторые функции перед вызовом метода add для BankAccounts
return this.bankAccounts.add();
},
findBankAccount(bankAccount) {
// некоторые функции перед вызовом метода find для BankAccounts
return this.carList.find();
},
getBankAccountsList() {< br /> // некоторые функции перед вызовом метода getList для BankAccounts
return this.carList.getList();
}
};

Подробнее можно узнать здесь

5. Шаблон стратегии. Шаблон стратегии используется для создания взаимозаменяемого семейства алгоритмов, из которых во время выполнения выбирается требуемый процесс.
Шаблон стратегии – это поведенческий шаблон проектирования, который позволяет выбирать алгоритм
во время выполнения. Он определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми. Стратегия позволяет алгоритму изменяться независимо от клиентов, которые его используют.

Когда использовать
Вы должны использовать этот шаблон, когда большинство ваших классов имеют связанное поведение.
Шаблон стратегии: преимущества
Стратегия Паттерн имеет ряд преимуществ, которые можно свести к
следующим пунктам:

– Легко переключаться между различными алгоритмами (стратегиями) во время выполнения, потому что вы используете полиморфизм с использованием интерфейсов.
– Чистый код, потому что вы избегаете условно-зараженного кода (не сложного).
– Более чистый код. код, потому что вы разделяете проблемы на классы (класс для каждой стратегии).
Теперь я собираюсь показать вам, как вы можете реализовать этот шаблон с помощью JavaScript, вы должны помнить, что в Javascript отсутствуют интерфейсы. Итак, вам нужно запрограммировать класс StrategyManager, который используется в качестве интерфейсов:

Подробнее можно узнать здесь.

Голова еще не болит 😵? Это займет у вас некоторое время, но я надеюсь, что вы хотя бы знаете 5 основных и распространенных шаблонов проектирования в Node.js. Лучший способ — начать программировать с ними. Шаблоны проектирования — отличная концепция, которую трудно применить, просто прочитав о них. Возьмите несколько примеров реализаций, которые вы найдете в Интернете, и создайте на их основе.
Отличным ресурсом является страница Данные. Они просматривают шаблоны и дают вам как концептуальные, так и реальные примеры. Их справочные материалы тоже великолепны.
Этот список не является исчерпывающим. В ближайшие дни мы постараемся рассказать о других шаблонах проектирования в Node.js. Чтобы узнать больше о шаблонах проектирования javascript, вы можете узнать больше о packtpub и logrocket.

Спасибо 👏, что дочитали до этого места. Если вам понравился этот пост, поделитесь, прокомментируйте и нажмите/удерживайте 👍 несколько раз (до 50 раз). . . Может быть, кому-то это поможет.
Следите за мной в Twitter и LinkedIn ✌️ . Подробнее можно узнать на Шомане.