Как Observer уведомляет объекты
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Observer Pattern (Паттерн Наблюдатель)
Observer (Наблюдатель) — это поведенческий паттерн проектирования, который обеспечивает механизм подписки на изменения. Когда состояние объекта меняется, все подписчики автоматически об этом уведомляются. Это основа реактивного программирования в Android.
Основная идея
Шаблон Observer состоит из двух ключевых участников:
- Subject (Издатель/Observable) — объект, за состоянием которого наблюдают
- Observer (Наблюдатель) — объект, который хочет узнать об изменениях
Когда Subject изменяется, он уведомляет всех Observer'ов через вызов их методов обратного вызова.
Механизм уведомления
// Шаг 1: Observer регистрируется (подписывается)
observer.subscribe(subject)
// Шаг 2: Subject меняет своё состояние
subject.setState(newValue)
// Шаг 3: Subject уведомляет всех Observer'ов
subject.notifyObservers() // вызывает update() на каждом observer
// Шаг 4: Каждый Observer реагирует на изменение
observer.update(newValue)
Классический пример реализации
// Интерфейс Observer
interface Observer {
fun update(newValue: String)
}
// Subject - издатель
class DataStore {
private var data: String = ""
private val observers = mutableListOf<Observer>()
// Метод для подписки
fun subscribe(observer: Observer) {
observers.add(observer)
}
// Метод для отписки
fun unsubscribe(observer: Observer) {
observers.remove(observer)
}
// Изменение состояния
fun setState(newValue: String) {
data = newValue
notifyObservers() // уведомляем всех
}
// Уведомление всех подписчиков
private fun notifyObservers() {
for (observer in observers) {
observer.update(data) // вызываем update() на каждом
}
}
}
// Конкретный Observer
class UIObserver(val name: String) : Observer {
override fun update(newValue: String) {
println("$name получил обновление: $newValue")
}
}
// Использование
val store = DataStore()
val ui1 = UIObserver("UI1")
val ui2 = UIObserver("UI2")
store.subscribe(ui1)
store.subscribe(ui2)
store.setState("Hello") // оба observer'а получат уведомление
// Вывод:
// UI1 получил обновление: Hello
// UI2 получил обновление: Hello
Observer в Android (современный подход с LiveData)
class UserViewModel : ViewModel() {
// LiveData автоматически уведомляет Observer'ов
private val _userLiveData = MutableLiveData<User>()
val userLiveData: LiveData<User> = _userLiveData
fun loadUser(userId: String) {
viewModelScope.launch {
val user = userRepository.getUser(userId)
_userLiveData.value = user // уведомляет всех Observer'ов
}
}
}
// В Activity/Fragment
class UserActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val viewModel = ViewModelProvider(this).get(UserViewModel::class.java)
// Observer подписывается на изменения
viewModel.userLiveData.observe(this) { user ->
// Автоматически вызывается при изменении userLiveData
displayUser(user)
}
viewModel.loadUser("123")
}
}
Observer с RxJava (реактивный подход)
// Observable - это наблюдаемый объект
val numberObservable: Observable<Int> = Observable.create { emitter ->
emitter.onNext(1)
emitter.onNext(2)
emitter.onNext(3)
emitter.onComplete()
}
// Observer подписывается
numberObservable.subscribe(
{ value -> println("Получено: $value") }, // onNext
{ error -> println("Ошибка: $error") }, // onError
{ println("Завершено") } // onComplete
)
// или с использованием оператора filter
numberObservable
.filter { it % 2 == 0 }
.subscribe { value -> println("Чётное: $value") }
Observer с Flow (Kotlin Coroutines)
class DataRepository {
private val _stateFlow = MutableStateFlow<String>("Initial")
val stateFlow: StateFlow<String> = _stateFlow.asStateFlow()
fun updateData(newValue: String) {
_stateFlow.value = newValue // уведомляет всех подписчиков
}
}
// В ViewModel
class DataViewModel(private val repo: DataRepository) : ViewModel() {
fun observeData() {
viewModelScope.launch {
repo.stateFlow.collect { value ->
// Вызывается каждый раз при изменении
println("Data: $value")
}
}
}
}
Поток выполнения уведомления
1. Subject меняет состояние
↓
2. Subject вызывает notifyObservers()
↓
3. notifyObservers() итерирует по списку Observer'ов
↓
4. Для каждого Observer вызывает observer.update()
↓
5. Каждый Observer реагирует на изменение (обновляет UI, логику и т.д.)
Схема взаимодействия
┌─────────────┐
│ Subject │
│ (состояние)│
└──────┬──────┘
│
│ subscribe()
├─────────┬──────────┬──────────┐
↓ ↓ ↓ ↓
Observer1 Observer2 Observer3 Observer4
(UI1) (Logger) (Database) (Analytics)
↑ ↑ ↑ ↑
└─────────┼──────────┼──────────┘
setState()
→ notifyObservers()
Преимущества Pattern
✅ Слабая связанность — Subject не знает деталей Observer'ов
✅ Динамическая подписка — Observer'ы могут подписаться/отписаться во время выполнения
✅ Множественная уведомления — одно изменение → все Observer'ы уведомлены
✅ Реактивность — автоматические обновления при изменении состояния
Недостатки
❌ Порядок уведомления — не гарантирован порядок вызова Observer'ов
❌ Performance — много Observer'ов → много уведомлений
❌ Утечки памяти — забытые подписки могут держать объекты в памяти
Best Practices
✅ Всегда отписывайся — отписывайся от Observer при уничтожении объекта
// Плохо - может быть утечка памяти
viewModel.userLiveData.observe(this) { user ->
displayUser(user)
}
// Хорошо - LiveData автоматически отписывает lifecycle-aware
// (это уже работает с observe())
✅ Используй lifecycle-aware компоненты — LiveData, StateFlow с viewModelScope
✅ Избегай блокирующих операций в observer.update()
Современные альтернативы
| Подход | Когда использовать |
|---|---|
| LiveData | Activity/Fragment, простые случаи |
| StateFlow | ViewModel, реактивный подход |
| Flow | Асинхронные операции, stream обработки |
| RxJava | Сложная реактивная логика |
Заключение
Observer Pattern — фундаментальный паттерн для уведомления об изменениях. Современный Android использует LiveData и Flow вместо классической реализации, но принцип остаётся неизменным: Subject уведомляет всех зарегистрированных Observer'ов через вызов их callback методов. Это основа реактивного программирования и MVC архитектуры в Android.