Pull to refresh
827.91
OTUS
Цифровые навыки от ведущих экспертов

Паттерны проектирования в JS: паттерны создания объектов

Reading time 5 min
Views 14K
Итак, хабровчане, уже в этот четверг в OTUS стартует курс «Fullstack разработчик JavaScript». И сегодня мы делимся с вами еще одной авторской публикацией в преддверии старта курса.



Автор статьи: Павел Якупов


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

Говоря проще, паттерны проектирования — это удачные решения, которые используются достаточно часто. Паттерны проектирования как понятие сформировались еще в то время, когда языка программирования JavaScript не было в помине, в сфере software engineering паттерны проектирования были подробно описаны еще в 1994 году «Большой четверкой». Однако мы в нашей статье обратимся к реализации некоторых несложных паттернов именно на языке программирования JavaScript.

Быстро пробежимся по основным видам паттернов проектирования:

Паттерны проектирования создания


Как понятно из названия, данные паттерны в основном применяются для создания новых объектов. К ним относится такие паттерны, как Конструктор, Фабрика, Прототип и Синглетон.

Структурные паттерны проектирования


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

Паттерны проектирования поведения


Этот вид паттернов проектирования направлен на то, что бы улучшить коммуникацию между различными объектами. К паттернам проектирования поведения относятся Командир, Итератор, Медиатор, Обзервер, Паттерн Состояния, Стратегия и Шаблон.

В данной статье мы разбираем только паттерны проектирования, связанные с созданием объектов — потому что они немного проще и лучше подходят новичкам, чтобы начать создавать свои to-do приложения, текстовые RPG в консоли, простые игры на Canvas, и т.д.

Паттерн «Модуль»


Этот паттерн проектирования появился в языке JavaScript, так сказать, поневоле. Изначально в языке не было продумано противодействия таким явлениям, как загрязнение глобальной области видимости(а в других языках, таких как С# или С++ существуют namespace, которые решают эту проблему «из коробки»). Кроме того, модули частично необходимы для реиспользования кода, потому как их можно после первого создания и использования их можно подключать к проектам других команд, используя человеко-часы куда более грамотно.
Паттерн модуль все время своего существования(уже в ES5 он широко использовался) использовал IIFE(немедленно вызываемые функциональные выражения).

Приведем простой пример паттерна «Модуль»:

const first_Module = (function() {
let Surname = "Ivanov";
let Nickname = "isakura313";
  function declare_Surname() {
    console.log(Surname);
  }
  return {
    declare_Nickname: function() {
      alert(Nickname);
    }
  }
})();
first_Module.declare_Nickname();
console.log(Surname); // а вот тут уже нет доступа

Паттерн «Модуль» полностью инкапсулирует данные, которые заключены в нем. Мы можем обращаться к ним только с помощью публичных методов, и пока в JavaScript не появится реализации публичных и приватных методов «из коробки» придется реализовывать модуль таким образом.

Паттерн «Конструктор»


Это паттерн проектирования, предназначенный для создания объекта. Конструктором называется функция, которая создает новые объекты. Однако в JavaScript объекты могут быть созданы «на лету», даже без функции-конструктора или определения класса.
Конструктор один из наиболее часто используемых паттернов проектирования. Он применяется для создания объектов определенного типа.

//представим что мы делаем маленькое to-do приложение
//итак, у нас есть класс, который  может создавать нам объекты с цветом и текстом дела
class ItemDeal {
  constructor(name, color) {
    this.name = name;
    this.color = color;
  }
}
 
//у нас есть класс как шаблон, но как нам заставить сохранять в localStorage эти данные?
let item = new ItemDeal(`${text}`, `${select.value - 1}`);  //где text - данные из инпута, a select.value - данные о цвете
let myJson = JSON.stringify(item); // чтобы у нас дела могли сохраняться в //localStorage, нам нужно упаковать только что созданный объект
//localStorage.setItem(item.name, myJson);

Паттерн «Фабрика»


Паттерн Фабрика это еще один паттерн сориентированный на создание объекта из класса. В нем мы предоставляем общие интерфейсы которые делегируют создание объекта подкласса(subclasses).

Данный паттерн проектирования чаще всего используется для того, чтобы манипулировать коллекцией объектов, которые имеют как различные, так и одинаковые характеристики.
В нижеприведенном примере мы создадим класс врага(EnemyFactory) для нашего текстового квеста. Да, пример достаточно простой, но в этом и заключается проблема паттернов проектирования: они нужны для «больших» приложений. Если у вас только три картинки вылетают по клику на странице — то никакие паттерны проектирования вам особо и не будут полезны.

Ладно, просто покажем кусочек кода нашей текстовой RPG в консоли:

class EnemyFactory{
constructor() {
    this.createEnemy = function(type) {
      let enemy;
      if (type === 'goblin' || type === 'ork') enemy = new Infantry();
      else if (type === 'elf') enemy = new Archer();
      enemy.attack = function() {
        return `The ${this._type} is attack`;
      };
      return enemy;
    };
  }
}
class Infantry {
  constructor() {
    this._type = 'goblin';
    this.scream = function() {
      return 'AAAAAAAAA! Za ordu!!!';
    };
  }
}
 
class Archer {
  constructor() {
    this._type = 'elf';
    this.magic_attack = function() {
      return 'Magic fog around you! You cant see!!';
    };
  }
}
 
const enemy_army = new EnemyFactory();
let newGoblin = enemy_army.createEnemy('goblin');
let newElf = enemy_army.createEnemy('elf');
console.log(newGoblin.attack());
console.log(newElf.attack());
console.log(newGoblin.scream());
console.log(newElf.magic_attack());
//произошло сражение

Паттерн «Прототип»


Здесь мы используем некоторый тип «скелета» настоящего объекта для создания нового объекта. А прототипирование это самый нативный тип выстраивания ООП в JavaScript.

//итак, мы продолжаем разработку нашего to-do приложения
const itemDeal = {
  colorOfHeader: blue; // и вк и фейсбук такие. Чем моё приложение хуже?
  create() {
    console.log("our item create");
    //создаем наш item
  },
  delete() {
    console.log("our item delete now");
     // удаляем наш item
  },
};
//однако заказчик вдруг попросил сделать так, что to-do могли
 //пользоваться несколько человек, как  сервис Trello.
const newDeal = Object.create(itemDeal, { owner: { value: 'Paul' } });
console.log(newDeal.__proto__ === itemDeal);  //true

Паттерн «Прототип» оказывается полезен, если в вашем приложении можно как-то расширить или уменьшить функциональность.

Паттерн «Одиночка»


Или, как он более известен, «Singleton». «Одиночка» это специальный паттерн в котором может существовать только один экземпляр класса. Паттерн работает следующим образом — инициализация объекта сработает, если не имеется ни одного экземпляра, созданного или возвращенного. Если имеется, то вернется инициированный объект.
Допустим мы создаем класс главного героя, и хотим, чтобы он был 1, а не 4, как в Джуманджи.

class Hero {
  constructor(name) {
    if (Hero.exists) {
      return Hero.instance;
    }
    this._name = name;
    Hero.instance = this;
    Hero.exists = true;
    return this;
  }
  getName() {
    return this._name;
  }
  setName(name) {
    this._name = name;
  }
}
//пора героям подать голос
const smolder = new Hero('Smolder!');
console.log(smolder.getName()); // Smolder!
 
const ruby = new Hero('Ruby');
console.log(ruby.getName()); //  Smolder!
//синглетон хорош, если у вас один герой в игре. Для Джуманджи он как раз бы и не подошел.
//но мне нужна была игра с несколькими персонажами для иллюстрации работы паттерна

Итак, всем спасибо за внимание! Надеюсь, кому-то эта статья послужит хорошим стартом в ООП на JavaScript(хоть, по честному признанию моего коллеги с многолетним опытом и на Java, и на JavaScript, ООП там, мягко говоря, не очень развитое). Однако в новых стандартах язык значительно улучшился, и я уверен, эта методология еще будет только чаще использоваться(или придет Dart и все заменит).

Полезные ссылки:

developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/create
learn.javascript.ru/class
developer.mozilla.org/ru/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
Tags:
Hubs:
+4
Comments 14
Comments Comments 14

Articles

Information

Website
otus.ru
Registered
Founded
Employees
101–200 employees
Location
Россия
Representative
OTUS