|
1 | | -# Lesson 25 |
| 1 | +--- |
| 2 | +title: Занятие 25 |
| 3 | +description: Связь модулей - от интерфейсов до EventBus |
| 4 | +--- |
| 5 | + |
| 6 | +# OTUS |
| 7 | + |
| 8 | +## Javascript Basic |
| 9 | + |
| 10 | +<!-- v --> |
| 11 | + |
| 12 | +## Вопросы? |
| 13 | + |
| 14 | +<!-- s --> |
| 15 | + |
| 16 | +## Связь модулей - от интерфейсов до EventBus |
| 17 | + |
| 18 | +<!-- s --> |
| 19 | + |
| 20 | +### Разберемся с задачей |
| 21 | + |
| 22 | +<!-- v --> |
| 23 | + |
| 24 | +Для начала два термина - **связность(_cohesion_)** и **связанность(_coupling_)**. |
| 25 | + |
| 26 | +[Связность](<https://ru.wikipedia.org/wiki/%D0%A1%D0%B2%D1%8F%D0%B7%D0%BD%D0%BE%D1%81%D1%82%D1%8C_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)>) - на сколько составные части направлены на решение одной задачи. |
| 27 | + |
| 28 | +[Связанность](<https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D1%86%D0%B5%D0%BF%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)>) - на сколько одни модули зависят от других (и как много они знают друг о друге) |
| 29 | + |
| 30 | +<!-- v --> |
| 31 | + |
| 32 | +[Качественный дизайн обладает слабой связанностью (low coupling) и сильной связностью (high cohesion).](https://medium.com/german-gorelkin/low-coupling-high-cohesion-d36369fb1be9) |
| 33 | + |
| 34 | +Это значит, что программный компонент имеет небольшое число внешних связей и отвечает за решение близких по смыслу задач. |
| 35 | + |
| 36 | +<!-- v --> |
| 37 | + |
| 38 | +**Слабое зацепление (Low Coupling)** и **Высокая связность (High Cohesion)** это 2 из 9 [**шаблонов GRASP**](<https://ru.wikipedia.org/wiki/GRASP#4._%D0%A1%D0%BB%D0%B0%D0%B1%D0%BE%D0%B5_%D0%B7%D0%B0%D1%86%D0%B5%D0%BF%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_(Low_Coupling)>) |
| 39 | + |
| 40 | +<!-- v --> |
| 41 | + |
| 42 | +Высокая связность говорит об эффективности программы (или ее отдельных модулей). |
| 43 | + |
| 44 | +Низкая связанность означает легкость рефакторинга и переиспользуемость кода. |
| 45 | + |
| 46 | +<!-- v --> |
| 47 | + |
| 48 | +### Вопросы? |
| 49 | + |
| 50 | +<!-- s --> |
| 51 | + |
| 52 | +### Наблюдатель (Observer) |
| 53 | + |
| 54 | +<!-- v --> |
| 55 | + |
| 56 | +[Наблюдатель](https://refactoring.guru/ru/design-patterns/observer) - подход (паттерн), позволяющий одним объектам следить и реагировать на события, происходящие в других объектах. |
| 57 | + |
| 58 | +<!-- v --> |
| 59 | + |
| 60 | +<img src="./images/ObservableUML.png" title="Observable UML" /> |
| 61 | + |
| 62 | +<!-- v --> |
| 63 | + |
| 64 | +На самом деле вы с ним уже работали - это [EventTarget](https://developer.mozilla.org/ru/docs/Web/API/EventTarget) |
| 65 | + |
| 66 | +<!-- v --> |
| 67 | + |
| 68 | +Данный шаблон часто применяют в ситуациях, в которых отправителя сообщений не интересует, что делают получатели с предоставленной им информацией. |
| 69 | + |
| 70 | +<!-- v --> |
| 71 | + |
| 72 | +Может быть представлен как |
| 73 | + |
| 74 | +<!-- eslint-skip --> |
| 75 | + |
| 76 | +```ts |
| 77 | +IObservable { |
| 78 | + addObserver(event, handler) |
| 79 | + removeObserver(event, handler) |
| 80 | + notifyObserver(event, data) |
| 81 | +} |
| 82 | +``` |
| 83 | + |
| 84 | +<!-- v --> |
| 85 | + |
| 86 | +или |
| 87 | + |
| 88 | +<!-- eslint-skip --> |
| 89 | + |
| 90 | +```ts |
| 91 | +EventTarget { |
| 92 | + addEventListener(event, handler) |
| 93 | + removeEventListener(event, handler) |
| 94 | + dispatchEvent(event) |
| 95 | +} |
| 96 | +``` |
| 97 | + |
| 98 | +<!-- v --> |
| 99 | + |
| 100 | +или |
| 101 | + |
| 102 | +<!-- eslint-skip --> |
| 103 | + |
| 104 | +```ts |
| 105 | +Backbone.Events { |
| 106 | + on(event, handler) |
| 107 | + off(event, handler) |
| 108 | + trigger(event) |
| 109 | +} |
| 110 | +``` |
| 111 | + |
| 112 | +<!-- v --> |
| 113 | + |
| 114 | +Иногда могут добавлять вспомогательные методы, например |
| 115 | + |
| 116 | +<!-- eslint-skip --> |
| 117 | + |
| 118 | +```ts |
| 119 | +Backbone.Events { |
| 120 | + // ... |
| 121 | + once(event, handler) |
| 122 | +} |
| 123 | +``` |
| 124 | + |
| 125 | +<!-- v --> |
| 126 | + |
| 127 | +```ts |
| 128 | +document.querySelector(element).addEventListener("click", (ev) => { |
| 129 | + alert("Boom!"); |
| 130 | +}); |
| 131 | +``` |
| 132 | + |
| 133 | +<!-- v --> |
| 134 | + |
| 135 | +Оговорка: чаще всего обработчиком события является функция. Но это также может быть и объект ([EventListener](https://developer.mozilla.org/ru/docs/Web/API/EventListener)) - в зависимости от реализации. |
| 136 | + |
| 137 | +<!-- v --> |
| 138 | + |
| 139 | +### Вопросы? |
| 140 | + |
| 141 | +<!-- s --> |
| 142 | + |
| 143 | +### Посредник (Mediator) |
| 144 | + |
| 145 | +<!-- v --> |
| 146 | + |
| 147 | +[Посредник](https://refactoring.guru/ru/design-patterns/mediator) - это поведенческий паттерн проектирования, который позволяет уменьшить связанность множества классов между собой, благодаря перемещению этих связей в один класс-посредник. |
| 148 | + |
| 149 | +<!-- v --> |
| 150 | + |
| 151 | +**Задача:** Обеспечить взаимодействие множества объектов, сформировав при этом слабую связанность и избавив объекты от необходимости явно ссылаться друг на друга. |
| 152 | + |
| 153 | +**Решение:** Создать объект, инкапсулирующий способ взаимодействия множества объектов. |
| 154 | + |
| 155 | +**Преимущества:** Устраняется связанность между "Коллегами", централизуется управление. |
| 156 | + |
| 157 | +<!-- v --> |
| 158 | + |
| 159 | +Самый распространенный (и простой) вариант реализации паттерна - с использованием **EventEmitter** интерфейса (**Event Bus** - Шина событий). |
| 160 | + |
| 161 | +<!-- v --> |
| 162 | + |
| 163 | +Разница, по сравнению с обычным использованием EventTarget: |
| 164 | + |
| 165 | +- события в EventTarget генерирует сам объект, при работе с EventBus это делают сторонние объекты |
| 166 | +- список событий при работе с EventTarget ограничен устройством объекта, при работе с EventBus он определяется участниками |
| 167 | + |
| 168 | +<!-- v --> |
| 169 | + |
| 170 | +<img src="./images/EventBus.jpeg" title="Event Bus" /> |
| 171 | + |
| 172 | +<!-- v --> |
| 173 | + |
| 174 | +При этом, чтобы избежать коллизии имен событий, зачастую вводят `namespaces`, в формате **{NAMESPACE}:{EVENT NAME}**. Например `user:add`, `searchHistory:add`. |
| 175 | + |
| 176 | +Нужно отметить, что по-хорошему, префиксы делаются на основе сущностей, а не на основе модулей (иначе происходит раскрытие структуры системы). |
| 177 | + |
| 178 | +<!-- v --> |
| 179 | + |
| 180 | +```ts |
| 181 | +const eventBus = new EventBus(); |
| 182 | + |
| 183 | +// module 1 |
| 184 | +eventBus.on("city:changed", (cityName) => console.log(`New city: ${cityName}`)); |
| 185 | + |
| 186 | +// module 2 |
| 187 | +eventBus.trigger("city:changed", "Minsk"); |
| 188 | +``` |
| 189 | + |
| 190 | +<!-- v --> |
| 191 | + |
| 192 | +Как мы могли бы применить это к уже сделанным домашним заданиям? |
| 193 | + |
| 194 | +<!-- v --> |
| 195 | + |
| 196 | +### Вопросы? |
| 197 | + |
| 198 | +<!-- s --> |
| 199 | + |
| 200 | +### Практика |
| 201 | + |
| 202 | +<!-- v --> |
| 203 | + |
| 204 | +[Реализовать Event Emitter](https://codesandbox.io/s/github/vvscode/otus--javascript-basic/tree/master/lessons/lesson33/code/eventEmitter) |
| 205 | + |
| 206 | +<!-- v --> |
| 207 | + |
| 208 | +Реализовать поверх существующего функционала метод **once** (для одноразового вызова обработчика). |
| 209 | + |
| 210 | +<!-- v --> |
| 211 | + |
| 212 | +### Вопросы? |
| 213 | + |
| 214 | +<!-- s --> |
| 215 | + |
| 216 | +Дополнительные материалы: |
| 217 | + |
| 218 | +- [Backbone Events](https://backbonejs.org/#Events) и [исходники](https://backbonejs.org/docs/backbone.html#section-17) |
| 219 | +- [EventTarget simple implementation](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) |
| 220 | +- [Паттерны проектирования понятным языком](https://refactoring.guru/ru/design-patterns) |
| 221 | +- [Design patterns for humans!](https://github.com/sohamkamani/javascript-design-patterns-for-humans) |
| 222 | + |
| 223 | +<!-- v --> |
| 224 | + |
| 225 | +### Опрос о занятии |
0 commit comments