mirror of
https://github.com/tmrts/go-patterns.git
synced 2024-11-25 06:26:06 +03:00
Implement Observer pattern
This commit is contained in:
parent
befd460eeb
commit
065ae23a2f
@ -42,7 +42,7 @@ __Behavioral Patterns__:
|
|||||||
| TODO: [Command](behavioral/command.md) | Bundles a command and arguments to call later |
|
| TODO: [Command](behavioral/command.md) | Bundles a command and arguments to call later |
|
||||||
| TODO: [Mediator](behavioral/mediator.md) | Connects objects and acts as a proxy |
|
| TODO: [Mediator](behavioral/mediator.md) | Connects objects and acts as a proxy |
|
||||||
| TODO: [Memento](behavioral/memento.md) | Generate an opaque token that can be used to go back to a previous state |
|
| TODO: [Memento](behavioral/memento.md) | Generate an opaque token that can be used to go back to a previous state |
|
||||||
| TODO: [Observer](behavioral/observer.md) | Provide a callback for notification of events/changes to data |
|
| [Observer](behavioral/observer.md) | Provide a callback for notification of events/changes to data |
|
||||||
| TODO: [Registry](behavioral/registry.md) | Keep track of all subclasses of a given class |
|
| TODO: [Registry](behavioral/registry.md) | Keep track of all subclasses of a given class |
|
||||||
| TODO: [State](behavioral/state.md) | Encapsulates varying behavior for the same object based on its internal state |
|
| TODO: [State](behavioral/state.md) | Encapsulates varying behavior for the same object based on its internal state |
|
||||||
| [Strategy](behavioral/strategy.md) | Enables an algorithm's behavior to be selected at runtime |
|
| [Strategy](behavioral/strategy.md) | Enables an algorithm's behavior to be selected at runtime |
|
||||||
|
47
behavioral/observer.md
Normal file
47
behavioral/observer.md
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# Observer Pattern
|
||||||
|
|
||||||
|
The [observer pattern](https://en.wikipedia.org/wiki/Observer_pattern) allows a type instance to "publish" events to other type instances ("observers") who wish to be updated when a particular event occurs.
|
||||||
|
|
||||||
|
## Implementation
|
||||||
|
|
||||||
|
In long-running applications—such as webservers—instances can keep a collection of observers that will receive notification of triggered events.
|
||||||
|
|
||||||
|
Implementations vary, but interfaces can be used to make standard observers and notifiers:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type (
|
||||||
|
// Event defines an indication of a point-in-time occurrence.
|
||||||
|
Event struct {
|
||||||
|
// Data in this case is a simple int, but the actual
|
||||||
|
// implementation would depend on the application.
|
||||||
|
Data int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Observer defines a standard interface for instances that wish to list for
|
||||||
|
// the occurrence of a specific event.
|
||||||
|
Observer interface {
|
||||||
|
// OnNotify allows an event to be "published" to interface implementations.
|
||||||
|
// In the "real world", error handling would likely be implemented.
|
||||||
|
OnNotify(Event)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notifier is the instance being observed. Publisher is perhaps another decent
|
||||||
|
// name, but naming things is hard.
|
||||||
|
Notifier interface {
|
||||||
|
// Register allows an instance to register itself to listen/observe
|
||||||
|
// events.
|
||||||
|
Register(Observer)
|
||||||
|
// Deregister allows an instance to remove itself from the collection
|
||||||
|
// of observers/listeners.
|
||||||
|
Deregister(Observer)
|
||||||
|
// Notify publishes new events to listeners. The method is not
|
||||||
|
// absolutely necessary, as each implementation could define this itself
|
||||||
|
// without losing functionality.
|
||||||
|
Notify(Event)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
For usage, see [observer/main.go](observer/main.go) or [view in the Playground](https://play.golang.org/p/cr8jEmDmw0).
|
93
behavioral/observer/main.go
Normal file
93
behavioral/observer/main.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// Package main serves as an example application that makes use of the observer pattern.
|
||||||
|
// Playground: https://play.golang.org/p/cr8jEmDmw0
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// Event defines an indication of a point-in-time occurrence.
|
||||||
|
Event struct {
|
||||||
|
// Data in this case is a simple int, but the actual
|
||||||
|
// implementation would depend on the application.
|
||||||
|
Data int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Observer defines a standard interface for instances that wish to list for
|
||||||
|
// the occurrence of a specific event.
|
||||||
|
Observer interface {
|
||||||
|
// OnNotify allows an event to be "published" to interface implementations.
|
||||||
|
// In the "real world", error handling would likely be implemented.
|
||||||
|
OnNotify(Event)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notifier is the instance being observed. Publisher is perhaps another decent
|
||||||
|
// name, but naming things is hard.
|
||||||
|
Notifier interface {
|
||||||
|
// Register allows an instance to register itself to listen/observe
|
||||||
|
// events.
|
||||||
|
Register(Observer)
|
||||||
|
// Deregister allows an instance to remove itself from the collection
|
||||||
|
// of observers/listeners.
|
||||||
|
Deregister(Observer)
|
||||||
|
// Notify publishes new events to listeners. The method is not
|
||||||
|
// absolutely necessary, as each implementation could define this itself
|
||||||
|
// without losing functionality.
|
||||||
|
Notify(Event)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
eventObserver struct{
|
||||||
|
id int
|
||||||
|
}
|
||||||
|
|
||||||
|
eventNotifier struct{
|
||||||
|
// Using a map with an empty struct allows us to keep the observers
|
||||||
|
// unique while still keeping memory usage relatively low.
|
||||||
|
observers map[Observer]struct{}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (o *eventObserver) OnNotify(e Event) {
|
||||||
|
fmt.Printf("*** Observer %d received: %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() {
|
||||||
|
// Initialize a new Notifier.
|
||||||
|
n := eventNotifier{
|
||||||
|
observers: map[Observer]struct{}{},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register a couple of observers.
|
||||||
|
n.Register(&eventObserver{id: 1})
|
||||||
|
n.Register(&eventObserver{id: 2})
|
||||||
|
|
||||||
|
// A simple loop publishing the current Unix timestamp to observers.
|
||||||
|
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()})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user