Паттерн Observer (Наблюдатель) позволяет экземпляру типа "публиковать" события для других экземпляров типа ("наблюдателей"), которые хотят быть обновленными, когда происходит определенное событие.
Реализация
В долго работающих приложениях, таких как экземпляры веб-серверов, можно хранить коллекцию наблюдателей, которые будут получать уведомления о запущенных событиях.
Реализации различаются, но интерфейсы могут использоваться для создания стандартных наблюдателей (observers) и уведомителей (notifiers):
type (
// Event определяет индикацию
// возникновения момента времени.
Event struct {
// Data в этом примере простой int, но в действительной
// реализации это будет зависеть от приложения.
Data int64
}
// Observer определяет стандартный интерфейс
// для экземпляров, которые хотят
// быть в списке оповещения о возникновении
// определенного события.
Observer interface {
// OnNotify позволяет событию
// быть "опубликованным" для реализаций интерфейса.
// В "реальном мире" здесь скорее всего
// будет реализована обработка ошибок.
OnNotify(Event)
}
// Notifier - это наблюдаемый экземпляр.
Notifier interface {
// Register позволяет экземпляру зарегистрироваться
// для прослушивания/наблюдения за событиями.
Register(Observer)
// Deregister позволяет экземпляру
// удалить себя из коллекции
// наблюдателей/слушателей.
Deregister(Observer)
// Notify публикует новые события для слушателей.
// Метод не обязателен, так как
// каждая реализация может определить это сама
// без потери функциональности.
Notify(Event)
}
)
Использование
Ниже приведен пример использования паттерна Observer и ссылка песочницу на play.golang.org
// Package main слуджит примером приложения, которое использует паттерн observer.
// Песочница: https://play.golang.org/p/GWwjZENw978
package main
import (
"fmt"
"time"
)
type (
// Event определяет индикацию возникновения момента времени.
Event struct {
// Data в этом примере простой int, но в действительной
// реализации это будет зависеть от приложения.
Data int64
}
// Observer определяет стандартный интерфейс для экземпляров, которые хотят
// быть в списке оповещения о возникновении определенного события.
Observer interface {
// OnNotify позволяет событию быть "опубликованным" для реализаций интерфейса.
// В "реальном мире" здесь скорее всего будет реализована обработка ошибок.
OnNotify(Event)
}
// Notifier - это наблюдаемый экземпляр.
Notifier interface {
// Register позволяет экземпляру зарегистрироваться
// для прослушивания/наблюдения за событиями.
Register(Observer)
// Deregister позволяет экземпляру удалить себя из коллекции
// наблюдателей/слушателей.
Deregister(Observer)
// Notify публикует новые события для слушателей.
// Метод не обязателен, так как каждая реализация может определить это сама
// без потери функциональности.
Notify(Event)
}
)
type (
eventObserver struct{
id int
}
eventNotifier struct{
// Использование map с пустым struct позволяет хранить наблюдателей
// уникальными, использая при этом мало памяти.
observers map[Observer]struct{}
}
)
func (o *eventObserver) OnNotify(e Event) {
fmt.Printf("*** Observer %d получен: %d\n", o.id, e.Data)
}
func (o *eventNotifier) Register(l Observer) {
o.observers[l] = struct{}{}
}
func (o *eventNotifier) Deregister(l Observer) {
delete(o.observers, l)
}
func (p *eventNotifier) Notify(e Event) {
for o := range p.observers {
o.OnNotify(e)
}
}
func main() {
// Инициализируем новый Notifier.
n := eventNotifier{
observers: map[Observer]struct{}{},
}
// Регистрируем пару наблюдателей.
n.Register(&eventObserver{id: 1})
n.Register(&eventObserver{id: 2})
// Простой цикл, публикующий текущий Unix timestamp для наблюдателей.
stop := time.NewTimer(10 * time.Second).C
tick := time.NewTicker(time.Second).C
for {
select {
case <- stop:
return
case t := <-tick:
n.Notify(Event{Data: t.UnixNano()})
}
}
}
Вывод:
*** Observer 1 получен: 1257894001000000000
*** Observer 2 получен: 1257894001000000000
*** Observer 1 получен: 1257894002000000000
*** Observer 2 получен: 1257894002000000000
*** Observer 1 получен: 1257894003000000000
*** Observer 2 получен: 1257894003000000000
*** Observer 1 получен: 1257894004000000000
*** Observer 2 получен: 1257894004000000000
*** Observer 1 получен: 1257894005000000000
*** Observer 2 получен: 1257894005000000000
*** Observer 1 получен: 1257894006000000000
*** Observer 2 получен: 1257894006000000000
*** Observer 1 получен: 1257894007000000000
*** Observer 2 получен: 1257894007000000000
*** Observer 1 получен: 1257894008000000000
*** Observer 2 получен: 1257894008000000000
*** Observer 1 получен: 1257894009000000000
*** Observer 2 получен: 1257894009000000000
*** Observer 1 получен: 1257894010000000000
*** Observer 2 получен: 1257894010000000000
Читайте также:
- Паттерны в Golang: Object Pool (Пул объектов)
- Паттерны в Golang: Builder (Строитель)
- Паттерны в Golang: Factory Method (Фабричный метод)
Комментариев нет:
Отправить комментарий