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

Что нам нужно?

  • Функциональность разбита на независимые модули меньшего размера.
  • Слабосвязанная архитектура.
  • Независимость от фреймворка или библиотеки. Гибкость к изменениям в будущем.
  • Промежуточный уровень интерпретирует запросы. Модули не имеют прямого доступа к ядру или библиотекам.
  • Предотвратить падение приложений из-за ошибок с определенными модулями.

Зачем нам нужны шаблоны дизайна?

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

Происхождение узоров?

  • Ранние работы архитектора Кристофера Александра
  • Он создал язык шаблонов, который помог бы расширить возможности любого, кто желает проектировать и строить в любом масштабе.
  • В 1995 году Эрих, Ричард, Ральф и Джон - группа, получившая название Банда четырех ( или GoF для краткости) опубликовал Шаблоны проектирования: элементы многоразового объектно-ориентированного программного обеспечения

Это краткое руководство по шаблону проектирования. Если хотите, то почитайте поподробнее. Настоятельно рекомендую прочитать. Https://addyosmani.com/resources/essentialjsdesignpatterns/book/.

1. Шаблон конструктора

  • Конструктор - это специальный метод, используемый для инициализации вновь созданного объекта после того, как для него выделена память.
  • В JavaScript почти все является объектом.
  • Конструктор может использовать для установки значений свойств и методов элемента при первом создании объекта.
  • В Javascript мы можем создавать объекты, используя 3 типа:
var newObject = {};
 
// or
var newObject = Object.create( Object.prototype );
 
// or
var newObject = new Object();

Мы можем устанавливать / получать свойства объекта, используя следующие типы:

  • Точечная запись
// Set properties
newObject.someKey = “Hello World”;
// Get properties
var value = newObject.someKey;
  • Квадратная скобка
// Set properties
newObject[“someKey”] = “Hello World”;
// Get properties
var value = newObject[“someKey”]
Object.defineProperty( newObject, “someKey”, {
 value: “for more control of the property’s behavior”,
 writable: true,
 enumerable: true,
 configurable: true
});

Базовый конструктор

  • JavaScript не поддерживает концепцию классов, но поддерживает специальные функции конструктора, которые работают с объектами.
  • При вызове функции-конструктора с ключевым словом «new» функция ведет себя как конструктор.
  • ключевое слово this ссылается на новый создаваемый объект.
function Car( model, year, miles ) { 
  this.model = model;
  this.year = year;
  this.miles = miles; 
  this.toString = function () {
    return this.model + " " + this.miles;
  };
}
// We can create new instances of the car
var civic = new Car( "Honda Civic", 2009, 20000 );
console.log( civic.toString() );

Но приведенный выше код не сильно оптимизирует

Вы хотели банан, но получили гориллу, держащую банан и все джунгли.

  • такие функции, как toString (), переопределяются для каждого из новых объектов, созданных с помощью конструктора Car.
  • Это затрудняет наследование.

А вот и прототипы:

  • Почти все объекты в JavaScript содержат объект «прототип».
  • Когда мы вызываем конструктор JavaScript для создания объекта, все свойства прототипа конструктора становятся доступными для нового объекта.
function Car( model, year, miles ) {
  this.model = model;
  this.year = year;
  this.miles = miles;
}
// Object.prototype.newMethod
Car.prototype.toString = function () {
  return this.model + " has done " + this.miles + " miles";
};
var civic = new Car( "Honda Civic", 2009, 20000 ); 
console.log( civic.toString() );

2. Шаблон модуля

  • Модули - это взаимозаменяемые отдельные части более крупной системы, которые можно легко повторно использовать.
  • Модули являются неотъемлемой частью любой надежной архитектуры приложения и обычно помогают сохранять блоки кода проекта как четко разделенными, так и организованными .

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

Зачем нам IIFE в JS:

  • В JS нет модификаторов доступа.
  • Переменные и методы не могут быть общедоступными.
  • Переменные и методы не могут быть частными.
  • Шаблон Module изначально был определен как способ обеспечить как частную, так и публичную инкапсуляцию для классов в традиционной разработке программного обеспечения.
var myNamespace = (function () {
  var myPrivateVar, myPrivateMethod;
  myPrivateVar = 0;
  myPrivateMethod = function( foo ) {
      console.log( foo );
  };
  return {
    myPublicVar: "foo",
    myPublicFunction: function( bar ) {
      myPrivateVar++;
      myPrivateMethod( bar );
    }
  };
})();
  • В шаблоне объявленные переменные доступны только внутри модуля.
  • Переменные, определенные в возвращаемом объекте, доступны всем.
  • Это позволяет нам имитировать конфиденциальность.
  • Это идея истинной инкапсуляции, по крайней мере, с точки зрения JavaScript.

3. Паттерн Сингелтона

  • Он ограничивает создание экземпляра класса одним объектом.
  • Шаблон Singleton может быть реализован путем создания класса с методом, который создает новый экземпляр класса, если он не существует. Если экземпляр уже существует, он просто возвращает ссылку на этот объект.
  • Он служит пространством имен общего ресурса, которое отделяет код реализации от глобального пространства имен, чтобы обеспечить единую точку доступа для функций.
var mySingleton = (function () {
  // Instance stores a reference to the Singleton
  var instance;
  function init() { // Singleton };
  return {
    // Get the Singleton instance if one exists
    // or create one if it doesn't
    getInstance: function () {
      if ( !instance ) {  // check for the instance 
        instance = init(); // 
      }
      return instance;  
    }
  };
})();

4. Образец наблюдателя

Один или несколько наблюдателей интересуются состоянием предмета и регистрируют свой интерес к предмету, присоединяясь к нему. Когда что-то меняется в нашей теме, что может заинтересовать наблюдателя, отправляется сообщение с уведомлением, которое вызывает метод обновления в каждом наблюдателе. Когда наблюдателя больше не интересует состояние субъекта, он может просто отстраниться. Этот паттерн состоит из следующих компонентов:

  • Тема: ведет список наблюдателей, упрощает добавление и удаление наблюдателей.
  • Наблюдатель: предоставляет интерфейс обновления для объектов, которые должны быть уведомлены об изменениях состояния Субъекта.
  • ConcreteSubject: рассылает уведомления наблюдателям об изменениях состояния.
  • ConcreteObserver: хранит ссылку на ConcreteSubject, реализует интерфейс обновления для Observer, чтобы гарантировать, что состояние соответствует состоянию Subject.

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

// The Observer
function Observer(){
  this.update = function(){
    // ...
  };
}

Теперь мы пишем ObserverList, которым будет управлять субъект.

function ObserverList(){
  this.observerList = [];
}

ObserverList.prototype.add = function( obj ){
  return this.observerList.push( obj );
};
 
ObserverList.prototype.count = function(){
  return this.observerList.length;
};
ObserverList.prototype.get = function( index ){
  if( index > -1 && index < this.observerList.length ){
    return this.observerList[ index ];
  }
};
ObserverList.prototype.indexOf = function( obj, startIndex ){
  var i = startIndex;
 
  while( i < this.observerList.length ){
    if( this.observerList[i] === obj ){
      return i;
    }
    i++;
  }
  return -1;
};
 
ObserverList.prototype.removeAt = function( index ){
  this.observerList.splice( index, 1 );
};

И напоследок пишем тему:

function Subject(){
  this.observers = new ObserverList();
}
Subject.prototype.addObserver = function( observer ){
  this.observers.add( observer );
};
 
Subject.prototype.removeObserver = function( observer ){
  this.observers.removeAt( this.observers.indexOf( observer, 0 ) );
};
 
Subject.prototype.notify = function( context ){
  var observerCount = this.observers.count();
  for(var i=0; i < observerCount; i++){
    this.observers.get(i).update( context );
  }
};

Этот шаблон похож на реализацию PubSub, но в PubSub Subject уведомляет наблюдателей, находящихся в теме. Для этого поддерживайте объект темы, содержащий список подписчиков. Это еще один шаг вперед по вышеуказанному шаблону.

5. Шаблон посредника

  • В словаре посредник называется нейтральной стороной, которая помогает в переговорах и разрешении конфликтов. В нашем мире посредник - это шаблон поведенческого проектирования, который позволяет нам предоставлять унифицированный интерфейс, через который могут взаимодействовать различные части системы.
  • Посредник способствует слабой связи, гарантируя, что вместо того, чтобы компоненты явно ссылаться друг на друга, их взаимодействие обрабатывается через эту центральную точку.
  • Реальной аналогией может быть типичная система управления движением в аэропорту. Башня (Посредник) управляет тем, какие самолеты могут взлетать и приземляться, потому что все коммуникации (уведомления, которые прослушиваются или транслируются) осуществляются с самолетов на диспетчерскую вышку, а не с самолета на самолет. Централизованный контроллер - ключ к успеху этой системы, и это действительно роль, которую посредник играет в разработке программного обеспечения.
  • Но… Возможно, самым большим недостатком использования шаблона является то, что он может создать единую точку отказа. Размещение посредника между модулями также может вызвать снижение производительности, поскольку они всегда взаимодействуют косвенно. Из-за природы слабой связи сложно определить, как система может реагировать, только глядя на широковещательные передачи.
var orgChart = {
  addNewEmployee: function(){
    // getEmployeeDetail provides a view that users interact with
    var employeeDetail = this.getEmployeeDetail();
    // when the employee detail is complete, the mediator (the 'orgchart' object)
    // decides what should happen next
    employeeDetail.on("complete", function(employee){
      // set up additional objects that have additional events, which are used
      // by the mediator to do additional things
      var managerSelector = this.selectManager(employee);
      managerSelector.on("save", function(employee){
        employee.save();
      });
    });
  },
}

6. Выкройка прототипа

  • Он основан на прототипном наследовании, когда мы создаем объекты, которые действуют как прототипы для других объектов.
  • Это требует использования Object.create.
  • Стоит отметить, что прототипные отношения могут вызвать проблемы при перечислении свойств объектов и (как рекомендует Крокфорд) заключении содержимого цикла в проверку hasOwnProperty ().
  • Стоит отметить, что прототипные отношения могут вызвать проблемы при перечислении свойств объектов и (как рекомендует Крокфорд) заключении содержимого цикла в проверку hasOwnProperty ().
  • Object.create также позволяет нам легко реализовывать расширенные концепции, такие как дифференциальное наследование, когда объекты могут напрямую наследовать от других объектов.
var myCar = {
  name: "Ford Escort",
  drive: function () {
    console.log( "Weeee. I'm driving!" );
  },
  panic: function () {
    console.log( "Wait. How do you stop this thing?" );
  }
};
 
// Use Object.create to instantiate a new car
var yourCar = Object.create( myCar );
 
// Now we can see that one is a prototype of the other
console.log( yourCar.name );

7. Командный шаблон

  • Шаблон Command направлен на инкапсуляцию вызовов методов, запросов или операций в один объект и дает нам возможность как параметризовать, так и передавать вызовы методов, которые могут быть выполнены.
  • Общая идея, лежащая в основе шаблона Command, заключается в том, что он предоставляет нам средство для разделения ответственности за выдачу команд от всего, что выполняет команды, вместо этого делегируя эту ответственность различным объектам.
(function(){
  var carManager = {
    // request information
    requestInfo: function( model, id ){
      return "The information for " + model + " with ID " + id + " is foobar";
    },
    // purchase the car
    buyVehicle: function( model, id ){
      return "You have successfully purchased Item " + id + ", a " + model;
    },
    // arrange a viewing
    arrangeViewing: function( model, id ){
      return "You have successfully booked a viewing of " + model + " ( " + id + " ) ";
    }
  };
})();
carManager.execute = function ( name ) {
    return carManager[name] && carManager[name].apply( carManager, [].slice.call(arguments, 1) );
};
carManager.execute( "buyVehicle", "Ford Escort", "453543" );

8. Узор фасада

  • Удобные высокоуровневые интерфейсы для больших массивов кода, которые скрывают основную сложность
  • Когда вы возводите фасад, вы обычно создаете внешний вид, который скрывает иную реальность. Думайте об этом как об упрощении API, представленного другим разработчикам.
var module = (function () {  
    var _private = {  
        i: 5,
        get: function () {  
            console.log('current value:' + this.i);  
        },
        set: function (val) {  
            this.i = val;  
        },
        run: function () {  
            console.log('running');  
        },
        jump: function () {  
            console.log('jumping');  
        }  
    };
    return {  
        facade: function (args) {
        // set values of private properties 
        _private.set(args.val);
        // test setter
        _private.get();
        // optional: provide a simple interface
        // to internal methods through the
        // facade signature
            if (args.run) {  
                _private.run();  
            }  
        }  
    }
}());
  • Упрощает использование за счет ограниченного, более удобочитаемого API
  • Скрывает внутреннюю работу библиотеки. Делает реализацию менее важной.
  • Отличается от шаблона модуля, поскольку предоставляемый API может сильно отличаться от определенных общедоступных / частных методов.

9. Шаблон микширования

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

var myMixins = {
 
  moveUp: function(){
    console.log( "move up" );
  },
 
  moveDown: function(){
    console.log( "move down" );
  },
 
  stop: function(){
    console.log( "stop! in the name of love!" );
  }
 
};
// A skeleton carAnimator constructor
function CarAnimator(){
  this.moveLeft = function(){
    console.log( "move left" );
  };
}
// A skeleton personAnimator constructor
function PersonAnimator(){
  this.moveRandomly = function(){ /*..*/ };
}
// Extend both constructors with our Mixin
_.extend( CarAnimator.prototype, myMixins );
_.extend( PersonAnimator.prototype, myMixins );
// Now you can internalize the constructors 

Еще для чтения:

  1. Заводской образец
  2. Схема наилегчайшего веса
  3. Шаблон декоратора

Ссылка: