JavaScript

Шаблоны проектирования JavaScript, часть 1: Шаблон фабрика

Spread the love

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

Оригинальная статья: Babs CraigJavaScript Design Patterns Part 1: The Factory Pattern

Большинство шаблонов проектирования, которые мы рассмотрим, основаны на объектно-ориентированном программировании, и поэтому имеет смысл начинать с рассмотрения порождающего шаблона, который называется так, потому что шаблон предоставляет нам понятный интерфейс для создания объектов, абстрагируясь от сложности или логики, при его создание. Этот шаблон называется Factory Pattern (Фабричный шаблон) и позволяет легко создавать объекты в JavaScript.

И так давайте начнем.

Все примеры из этой серии будут доступны на Github здесь .

Чтобы запустить код из этой статьи, на вашем компьютере должен быть установлен Node. Следуйте этим инструкциям, если у вас его еще нет. Если вы будете следовать репо, вы найдете инструкции по запуску кода в файле readme.

Перво-наперво, давайте создадим папку. Мы можем назвать это javascript-design-pattern в этой папке, мы создадим папку factory.

Шаблон Фабрики в действии

Шаблон фабрики оборачивает конструктор для создания различных типов объектов и возвращает экземпляры объектов через простое API. Это позволяет легко создавать различные объекты, предоставляя простое API, которое возвращает указанный тип объекта.

Давайте начнем с создания наших конструкторов. Эти функции будут отвечать за возврат новых объектов определенного типа при вызове.

В папке factory давайте создадим файл laptop.js.

const Laptop = function({ ram, hdd, name }) {
  this.ram = ram || 0;
  this.hdd = hdd || 0;
  this.name = name || "";
};
module.exports = Laptop;

В этом файле мы создаем функцию конструктора Laptop. Он принимает объект в качестве параметра с атрибутами для создания экземпляра объекта с различными спецификациями, которые мы хотим записать — в данном случае, размер ОЗУ, размер жесткого диска и имя устройства.

После этого мы экспортируем функцию конструктора Laptop из модуля.

Давайте создадим еще один файл с именем tablet.js

Мы сделаем то же самое, но со спецификациями, более подходящими для планшета.

const Tablet = function({ ram, hdd, name, network }) {
    this.ram = ram || 0;
    this.hdd = hdd || 0;
    this.network = network || 0;
    this.name = name || "";
};
module.exports = Tablet;

Теперь, когда у нас есть наши конструкторы, давайте создадим фабричную функцию, которая предоставит API для создания новых экземпляров этих элементов. Добавьте новый файл с именем gadgetFactory.js

const Laptop = require("./laptop");
const Tablet = require("./tablet");
const gadget = { Laptop, Tablet };

module.exports = {
    createGadget(type, attributes) {
        const GadgetType = gadget[type];        
        return new GadgetType(attributes);
    }
};

Здесь мы начили с импорта конструкторов для создания объектов Laptop и Tablet. Затем мы создали объект гаджета, используя имена конструкторов в качестве ключей. Это позволило нам получить доступ к нужному типу конструктора с помощью gadget[type] — где в этом примере type будет либо «Laptop«, либо «Tablet«. Наконец, мы экспортируем объект из этого модуля с помощью метода createGadget. Этот метод принимает тип гаджета в качестве первого параметра и вызывает указанный тип конструктора при передаче ему атрибутов.

Вы должны заметить, что когда мы вызываем функцию с новым ключевым словом в Javascript, мы получаем взамен пустой объект с привязкой this, установленной в выполняемой функции. Этот уникальный вызов также создаст прототипную связь между функцией конструктора и любыми новыми объектами, которые мы создаем таким образом.

Также стоит отметить, что заглавная первая буква — это просто соглашение, а не требование. Это не делает ничего особенного, и мы могли бы также назвать функции с помощью camelCase, как мы обычно делаем с другими именами переменных и функций в JavaScript.

Теперь мы можем создать файл, который будет использовать наше API фабричного шаблона.

Создайте файл index.js и добавьте следующий код.

const gadgetFactory = require("./gadgetFactory");

const myLaptop = gadgetFactory.createGadget("Laptop", {
    ram: 8,
    ssd: 256,
    name: "Bab's MacBook Pro"
});

const myTablet = gadgetFactory.createGadget("Tablet", {
    ram: 4,
    hdd: 128,
    name: "Bab's iPad",
    network: '4G'
});

console.log(myLaptop);
console.log(myTablet);

Первое, что вы можете заметить, это то, что в этом файле нам не требуются напрямую конструкторы для ноутбуков и планшетов. Все, что нам нужно, это модуль gadgetFactory (с его методом createGadget). Используя этот метод, мы затем создаем два экземпляра ноутбука и планшета соответственно и выводим их на консоль.

Теперь в вашем терминале перейдите в папку javascript-design-patterns и введите:

$ node ./factory/index.js

Вы должны увидеть следующие записи в консоли:

Laptop { ram: 8, ssd: 256, name: 'Bab\'s MacBook Pro' }
Tablet { ram: 4, hdd: 128, network: '4G', name: 'Bab\'s iPad' }

Как вы можете видеть, мы создали один тип объекта Laptop, а также тип Tablet, каждый со своими спецификациями. Используя этот шаблон, вы можете создать столько объектов гаджетов, сколько нужно, каждый со своими спецификациями.

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

В этом примере мы использовали функции конструктора Javascript, но этот шаблон также может быть реализован с использованием прототипов. Мы рассмотрим это в следующей статье, когда проведем рефакторинг нашего кода, чтобы сделать его более эффективным.

Далее в этой серии мы рассмотрим популярный шаблон Publisher / Subscriber (или PubSub для краткости). Как всегда, я хотел бы услышать ваши мысли в комментариях ниже!

Обновление: вы можете найти вторую часть серии, посвященную шаблону Publisher/Subscriber, здесь.

Была ли вам полезна эта статья?
[6 / 5]

Spread the love
Editorial Team

Recent Posts

Vue 3.4 Новая механика v-model компонента

Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование​ v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…

11 месяцев ago

Анонс Vue 3.4

Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…

11 месяцев ago

Как принудительно пере-отобразить (re-render) компонент Vue

Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…

2 года ago

Проблемы с установкой сертификата на nginix

Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…

2 года ago

Введение в JavaScript Temporal API

Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…

2 года ago

Когда и как выбирать между медиа запросами и контейнерными запросами

Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…

2 года ago