Многие программисты либо думают, что паттерны проектирования — это пустая трата
времени, либо просто не знают о том, как применять их правильно. Однако использование
подходящего паттерна может помочь в написании более качественного и понятного кода,
который, за счёт понятности, легче будет поддерживать.
Самое важное здесь, пожалуй, то, что применение паттернов даёт разработчикам ПО нечто
вроде словаря общеизвестных терминов, которые весьма полезны, например, при разборе
чужого кода. Паттерны раскрывают предназначение тех или иных фрагментов программы
для тех, кто пытается разобраться с устройством какого-нибудь проекта.
Теперь, когда мы разобрались с тем, что такое паттерны проектирования, и с тем, для чего
они нужны, перейдём, собственно, к паттернам и к описанию их реализации с
использованием JavaScript.
Паттерн «Модуль»
privateMethod();
}
}
})();
myModule.publicMethod();
Так как перед нами IIFE, код выполняется немедленно и возвращаемый выражением объект
назначается константе myModule. Благодаря тому, что тут имеется замыкание, у
возвращённого объекта есть доступ к функциям и переменным, объявленных внутри IIFE,
даже после завершения работы IIFE.
После того, как этот код будет выполнен, myModule будет выглядеть следующим образом:
const myModule = {
publicMethod: function() {
privateMethod();
}};
Применение этого паттерна упрощает понимание того, какие функции и переменные модуля
общедоступны, что способствует улучшению читабельности кода.
const myRevealingModule = {
setName: publicSetName,
greeting: publicVar,
getName: publicGetName
};
myRevealingModule.setName('Mark');
// выводит Name: Mark
myRevealingModule.getName();
Модули в ES6
Модули ES6 хранятся в файлах. Один файл может содержать лишь один модуль. Всё, что
находится внутри модуля, по умолчанию является приватным. Функции, переменные и
классы можно делать публичными с использованием ключевого слова export. Код внутри
модуля всегда выполняется в строгом режиме.
▍Экспорт модуля
// utils.js
export const greeting = 'Hello World';
export function sum(num1, num2) {
console.log('Sum:', num1, num2);
return num1 + num2;
}
export function subtract(num1, num2) {
console.log('Subtract:', num1, num2);
return num1 - num2;
}
// Это - приватная функция
function privateLog() {
console.log('Private Function');
}
// utils.js
function multiply(num1, num2) {
console.log('Multiply:', num1, num2);
return num1 * num2;
}
function divide(num1, num2) {
console.log('Divide:', num1, num2);
return num1 / num2;
}
// Это приватная функция
function privateLog() {
console.log('Private Function');
}
export {multiply, divide};
▍Импорт модуля
Так же как существуют два способа экспорта есть и два способа импорта модулей
Так же, как существуют два способа экспорта, есть и два способа импорта модулей.
Делается это с использованием ключевого слова import:
// main.js
// Импорт нескольких избранных элементов
import { sum, multiply } from './utils.js';
console.log(sum(3, 7));
console.log(multiply(3, 7));
// main.js
// импорт всего, что экспортирует модуль
import * as utils from './utils.js';
console.log(utils.sum(3, 7));
console.log(utils.multiply(3, 7));
Если имена экспортируемых в код функций или переменных могут вызвать коллизию, их
можно изменить при экспорте или при импорте.
// utils.js
function sum(num1, num2) {
console.log('Sum:', num1, num2);
return num1 + num2;
}
function multiply(num1, num2) {
console.log('Multiply:', num1, num2);
return num1 * num2;
}
export {sum as add, multiply};
Для переименования сущностей при импорте используется такая конструкция:
// main.js
import { add, multiply as mult } from './utils.js';
console.log(add(3, 7));
console.log(mult(3, 7));
Паттерн «Синглтон»
Паттерн «Синглтон» или «Одиночка» (Singleton) представляет собой объект, который может
существовать лишь в единственном экземпляре. В рамках применения этого паттерна
новый экземпляр некоего класса создаётся в том случае, если он пока не создан. Если же
экземпляр класса уже существует, то, при попытке обращения к конструктору, возвращается
ссылка на соответствующий объект. Последующие вызовы конструктора всегда будут
возвращать тот же самый объект.
const user = {
name: 'Peter',
age: 25,
job: 'Teacher',
greet: function() {
console.log('Hello!');
}
};
Так как каждый объект в JavaScript занимает собственную область памяти и не делит её с
другими объектами, всякий раз, когда мы обращаемся к переменной user, мы получаем
ссылку на один и тот же объект.
instance = this;
this.name = name;
this.age = age;
return instance;
}
const user1 = new User('Peter', 25);
const user2 = new User('Mark', 24);
// выводит true
console.log(user1 === user2);
Паттерн «Фабрика»
Этот паттерн используется для создания объектов в случаях, когда не нужно делать
общедоступной логику их создания. Паттерн «Фабрика» может быть использован в том
случае, если нужно создавать различные объекты в зависимости от специфических
условий. Например:
class Car{
constructor(options) {
this.doors = options.doors || 4;
this.state = options.state || 'brand new';
this.color = options.color || 'white';
}
}
class Truck {
constructor(options) {
this.doors = options.doors || 4;
this.state = options.state || 'used';
this.color = options.color || 'black';
}
}
class VehicleFactory {
createVehicle(options) {
if(options.vehicleType === 'car') {
return new Car(options);
} else if(options.vehicleType === 'truck') {
return new Truck(options);
}
}
}
k
Здесь созданы классы Car и Truck, которые предусматривают использование неких
стандартных значений. Они применяются для создания объектов car и truck. Также здесь
объявлен класс VehicleFactory, который используется для создания новых объектов на
основе анализа свойства vehicleType, передаваемого соответствующему методу
возвращаемого им объекта в объекте с параметрами options. Вот как со всем этим
работать:
Здесь создан объект factory класса VehicleFactory. После этого можно создавать
объекты классов Car или Truck, вызывая метод factory.createVehicle() и передавая
ему объект options со свойством vehicleType, установленным в значение car или truck.
Паттерн «Декоратор»
function Car(name) {
this.name = name;
// Значение по умолчанию
this.color = 'White';
}
// Создание нового объекта, который планируется декорировать
class Car() {
}
class CarWithAC() {
}
class CarWithAutoTransmission {
}
class CarWithPowerLocks {
}
class CarWithACandPowerLocks {
}
class Car {
constructor() {
// Базовая стоимость
this.cost = function() {
return 20000;
}
}
}
// Функция-декоратор
function carWithAC(car) {
car.hasAC = true;
const prevCost = car.cost();
car.cost = function() {
return prevCost + 500;
}
}
// Функция-декоратор
function carWithAutoTransmission(car) {
car.hasAutoTransmission = true;
const prevCost = car.cost();
car.cost = function() {
return prevCost + 2000;
}
}
// Функция-декоратор
function carWithPowerLocks(car) {
car.hasPowerLocks = true;
const prevCost = car.cost();
car.cost = function() {
return prevCost + 500;
}
}
Здесь мы сначала создаём базовый класс Car, используемый для создания объектов,
представляющих автомобили в стандартной комплектации. Затем создаём несколько
функций-декораторов, которые позволяют расширять объекты базового класса Car
дополнительными свойствами. Эти функции принимают соответствующие объекты в
качестве параметров. После этого мы добавляем в объект новое свойство, указывающее на
то, какой новой возможностью будет оснащён автомобиль, и переопределяем функцию
cost объекта, которая теперь возвращает новую стоимость автомобиля. В результате, для
того, чтобы «оснастить» автомобиль стандартной конфигурации чем-то новым, мы можем
Итоги
Теги: JavaScript, разработка
+24 66 2k 317
+24 66,2k 317
Редакторский дайджест
Присылаем лучшие статьи раз в месяц
Электропочта
@ru_vds
Пользователь
RUVDS.com
RUVDS – хостинг VDS/VPS серверов
Комментарии 27
ПОХОЖИЕ ПУБЛИКАЦИИ
29 марта 2019
2 октября 2018
6 августа 2018
вчера в 10:57
У й М
Успей пустить по Марсу
вчера в 18:01
вчера в 11:05
вчера в 11:59
вчера в 19:42
Настройка языка
Техническая поддержка
Полная версия
© 2006–2020 «Habr»