В этом видео мы с вами разберем такой паттерн, как Observer. Он достаточно сильно похож на Pub/Sub, но его идея немного в другом.
Каждый день, при разработке, у нас возникает проблема, когда у нас есть разные части приложения, которые должны реагировать на разные события. Например, пользователь ввел какой-то текст, и вам нужно изменить несколько компонентов. И, достаточно сложно, все это синхронизировать.
В этом нам может помочь Observer pattern. Он позволяет делать связи один ко многим между компонентами.
Мы хотим реализовать класс, у которого будут такие методы.
const observer = new EventObserver()
observer.subscribe(data => {
console.log('subscribe was fired', data)
})
observer.broadcast({someData: 'hello'})
То есть мы создаем один обсервер и потом в нескольких местах подписываемся на события этого обсервера с помощью subscribe. Поэтому когда мы вызовем observer.broadcast, то это уведомит всех подписчиков.
Давайте попробуем реализовать этот паттерн самостоятельно.
class EventObserver {
constructor () {
this.observers = []
}
subscribe (fn) {
this.observers.push(fn)
}
unsubscribe (fn) {
this.observers = this.observers.filter(subscriber => subscriber !== fn)
}
broadcast (data) {
this.observers.forEach(subscriber => subscriber(data))
}
}
Мы создали класс, в котором мы храним массив подписчиков. Также мы описали методы subscribe, unsubscribe и broadcast.
Теперь давайте проверим, что этот код работает.
const observer = new EventObserver()
observer.subscribe(data => {
console.log('subscribe for module 1 fired', data)
})
observer.subscribe(data => {
console.log('subscribe for module 2 fired', data)
})
observer.broadcast({someData: 'hello'})
Если мы посмотрим в браузер, то мы видим два консоль лога с данными.
Теперь давайте попробуем на реальном примере. Мы хотим написать 2 компонента: в одном мы будем вводить данные, а другой будет выводить количество введенных слов.
Для начала давайте добавим 2 элемента в нашу разметку.
<textarea class='textField'></textarea>
<div>
Words Count:
<p class='countField'></p>
</div>
Теперь давайте создадим новый Observer и найдем наши 2 элемента.
const blogObserver = new EventObserver()
const textField = document.querySelector('.textField')
const countField = document.querySelector('.countField')
Теперь мы хотим подписаться на наш blogObserver.
blogObserver.subscribe(text => {
console.log('broadcast catched')
})
И файрить broadcast, когда мы меняем текстовое поле
textField.addEventListener('keyup', () => {
blogObserver.broadcast(textField.value)
})
Внутрь broadcast, в качестве данных, мы передали значение поля.
Если мы посмотрим в браузер, то при вводе данных у нас стреляет наш console.log. Это значит, что наш broadcast работает.
Теперь мы хотим из текста найти количество слов. Давайте напишем дополнительную функцию для этого.
const getWordsCount = text =>
text ? text.trim().split(/\s+/).length : 0
И вызовем ее внутри subscribe.
blogObserver.subscribe(text => {
countField.innerHTML = getWordsCount(text)
})
Если мы посмотрим в браузер, то все работает и количество слов меняется.
И, хоть это маленький пример, он отлично показывает как работает Observer паттерн.
Если у вас возникли какие-то вопросы или комментарии, пишите их прямо под этим видео.