Ответ
Наблюдатель (Observer) — поведенческий паттерн, позволяющий объектам подписываться на события других объектов и реагировать на их изменения.
interface Observer {
fun update(data: String)
}
class Subject {
private val observers = mutableListOf<Observer>()
private var state: String = ""
fun setState(newState: String) {
state = newState
notifyObservers()
}
fun addObserver(observer: Observer) {
observers.add(observer)
}
private fun notifyObservers() {
observers.forEach { it.update(state) }
}
}
class ConcreteObserver : Observer {
override fun update(data: String) {
println("Received update: $data")
}
}
// Использование:
val subject = Subject()
val observer = ConcreteObserver()
subject.addObserver(observer)
subject.setState("New State") // Выведет: "Received update: New State"
Применение: уведомления UI о изменениях данных, события в EventBus, LiveData в Android.
Ответ 18+ 🔞
А, слушай, вот паттерн, который реально жизнь упрощает, если его правильно прикрутить. Называется «Наблюдатель», или Observer, если по-умному. Суть проще пареной репы, но гениальная, ёпта.
Представь себе такую ситуацию: есть у тебя один главный объект — Subject (или «Издатель»). Он типа как центр вселенной, в котором хранится какое-то важное состояние. И есть куча других объектов — Observers («Наблюдатели» или «Подписчики»), которым позарез нужно знать, когда это состояние меняется. Они как назойливые родственники, которые хотят быть в курсе всех твоих дел.
Вот этот главный объект не должен бегать за каждым подписчиком и кричать «Эй, у меня данные поменялись!». Это же пиздопроебина получается, он только этим и будет заниматься. Вместо этого он заводит себе список этих самых наблюдателей. Кто хочет знать о изменениях — тот пусть приходит и говорит: «Братан, добавь меня в список, я твой фанат». Это метод addObserver.
А когда у главного объекта меняется его внутреннее состояние (через setState), он просто проходит по своему списку фанатов и каждому тихонько так говорит: «Эй, дружок, данные обновились, вот держи». Это метод notifyObservers. А наблюдатели уже сами решают, что им с этой информацией делать — обновить интерфейс, записать в лог или просто охуеть от удивления.
Вот смотри на код, тут всё наглядно. Объявляем интерфейс Observer. Это такой контракт: «Мужик, если хочешь быть наблюдателем, у тебя ДОЛЖЕН быть метод update(data: String). А что ты в нём делаешь — твои проблемы».
interface Observer {
fun update(data: String)
}
Потом делаем самого «босса» — класс Subject. У него три дела:
- Хранить состояние (
state). - Хранить список подписчиков (
observers). - Когда состояние меняется — орать об этом всем в списке.
class Subject {
private val observers = mutableListOf<Observer>() // Список подхалимов
private var state: String = "" // Самое важное, за чем все следят
fun setState(newState: String) {
state = newState // Меняем состояние
notifyObservers() // И орём всем: "Чуваки, всё изменилось!"
}
fun addObserver(observer: Observer) {
observers.add(observer) // Новый фанат в клуб
}
private fun notifyObservers() {
observers.forEach { it.update(state) } // Проходим по списку и пинаем каждого
}
}
Ну и конкретный наблюдатель, который, допустим, просто выводит сообщение в консоль. Скучный тип.
class ConcreteObserver : Observer {
override fun update(data: String) {
println("Received update: $data") // Получил уведомление и вывел
}
}
А вот как это всё в жизни работает:
val subject = Subject() // Создаём главный объект
val observer = ConcreteObserver() // Создаём одного любопытного
subject.addObserver(observer) // Подписываем его на обновления
subject.setState("New State") // Меняем состояние -> наблюдатель получает пинок и выводит: "Received update: New State"
Где это полезно, спросишь? Да овердохуища где!
- UI в мобилках (типа Android с LiveData): Твоя разметка (View) подписывается на данные (ViewModel). Данные изменились — View сама перерисовывается. Волнение ебать от такой магии, правда?
- Разные EventBus'ы: Один компонент кинул событие (
setState("USER_CLICKED")), а двадцать других его тут же обработали. - Любая система уведомлений: Чат, почта, оповещения в играх. Всё построено на этой идее.
Главная фишка в том, что издатель и подписчики не знают друг о друге подробностей. Издателю да похуй, кто там в списке — он просто вызывает метод update. А подписчику да похуй, как именно издатель устроен внутри — он просто получает данные. Связь слабая, и это охуенно.
Просто не наделай классических ошибок: не забудь отписывать наблюдателей, когда они больше не нужны, а то будет утечка памяти, и приложение накроется медным тазом. И следи, чтобы в цикле уведомлений один наблюдатель случайно не поменял состояние издателя снова — будет бесконечный цикл, пидарас шерстяной.
Короче, паттерн мощный, как хуй с горы. Используй.