Разработка большого веб-приложения - серьезная проблема на предприятии. Размер команды увеличивается, функции начинают перегружать приложение, качество кода и управление день за днем становятся все жестче. Итак, что может быть хорошим шаблоном проектирования для вашего программного обеспечения в настоящее время. Какая формула может решить вашу проблему и ускорить развитие со временем ..?
Что нам нужно?
- Функциональность разбита на независимые модули меньшего размера.
- Слабосвязанная архитектура.
- Независимость от фреймворка или библиотеки. Гибкость к изменениям в будущем.
- Промежуточный уровень интерпретирует запросы. Модули не имеют прямого доступа к ядру или библиотекам.
- Предотвратить падение приложений из-за ошибок с определенными модулями.
Зачем нам нужны шаблоны дизайна?
- Это многоразовое решение, которое можно применить к часто возникающим проблемам при разработке программного обеспечения.
- Шаблоны бывают проверенные, выразительные, многоразовые и предложить ценность.
- Код становится более выразительным, инкапсулированным и структурированным. .
- При создании или поддержке решений один из самых эффективных подходов к объединению всех разработчиков или групп вашей организации на одной странице создает шаблоны дизайна.
- Одним из наиболее важных аспектов написания поддерживаемого кода является возможность замечать повторяющиеся темы в этом коде и оптимизировать им.
Происхождение узоров?
- Ранние работы архитектора Кристофера Александра
- Он создал язык шаблонов, который помог бы расширить возможности любого, кто желает проектировать и строить в любом масштабе.
- В 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.define Подробнее здесь
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. Шаблон модуля
- Модули - это взаимозаменяемые отдельные части более крупной системы, которые можно легко повторно использовать.
- Модули являются неотъемлемой частью любой надежной архитектуры приложения и обычно помогают сохранять блоки кода проекта как четко разделенными, так и организованными em. >.
Но прежде чем идти дальше, давайте взглянем на 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
Еще для чтения:
- Заводской образец
- Схема наилегчайшего веса
- Шаблон декоратора