观察者模式
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。
当新类型的观察者出现时,主题的代码不需要改变,我们需要做的是在新的类里实现观察者的接口,然后注册给主题即可。主题不在乎别的,它只会发送通知给所有实现了观察者接口的对象。
改变主题或观察者其中一方,并不会影响另一方,因为两者是松耦合的,只要它们之间的接口仍被遵守,我们就可以自由地改变它们。
接口设计
- 主题:
我们的主题应该至少拥有以下三个方法:
type subject interface {
registerObserver(string, observer)
removeObserver(string)
notifyObservers()
}
- 观察者
观察者需要拥有update方法,以便主题调用该方法来更新观察者
type observer interface {
update(float64, float64, float64)
}
具体实现
假设我们有一个weatherData类,这个类用来获取气象信息,一旦气象信息被改变,就通知所有注册给weatherData观察者
type weatherData struct {
tem float64
hum float64
pre float64
observers map[string]observer
}
func (w *weatherData) init() {
w.observers = map[string]observer{}
}
func (w *weatherData) registerObserver(name string, o observer) {
w.observers[name] = o
}
func (w *weatherData) removeObserver(name string) {
delete(w.observers, name)
}
func (w *weatherData) notifyObservers() {
for k, v := range w.observers {
fmt.Printf("notify observer %+v ...\n", k)
v.update(w.tem, w.hum, w.pre)
fmt.Printf("notify observer %+v success\n", k)
}
}
func (w *weatherData) measurementsChanged() {
w.notifyObservers()
}
func (w *weatherData) setMeasurements(tem, hum, pre float64) {
w.tem = tem
w.hum = hum
w.pre = pre
w.measurementsChanged()
}
可以看到,weatherData实现了主题的所有方法,并且有一个setMeasurements方法,一旦这个方法被调用,就会通知所有注册给它的观察者
看下观察者的实现:
type displayElement interface {
display()
}
type currentConditionDisplay struct {
tem float64
hum float64
sub subject
}
func (c *currentConditionDisplay) display() {
fmt.Printf("current condition display: temprature:%+v, humidity:%+v\n", c.tem, c.hum)
}
func (c *currentConditionDisplay) update(tem, hum, sub float64) {
c.tem = tem
c.hum = hum
c.display()
}
type forecastDisplay struct {
tem float64
hum float64
sub subject
}
func (f *forecastDisplay) display() {
fmt.Printf("forecast display: temprature:%+v, humidity:%+v\n", f.tem, f.hum)
}
func (f *forecastDisplay) update(tem, hum, sub float64) {
f.tem = tem
f.hum = hum
f.display()
}
实际上观察者实现了displayElement和observer两个接口,这时我们整合下代码:
wd := &weatherData{}
wd.init()
ccd := ¤tConditionDisplay{
sub: wd,
}
fd := &forecastDisplay{
sub: wd,
}
ccd.sub.registerObserver("currentConditionDisplay", ccd)
ccd.sub.registerObserver("forecastDisplay", fd)
wd.setMeasurements(10.1, 20.2, 30.3)
运行之,结果为:
notify observer currentConditionDisplay ...
current condition display: temprature:10.1, humidity:20.2
notify observer currentConditionDisplay success
notify observer forecastDisplay ...
forecast display: temprature:10.1, humidity:20.2
notify observer forecastDisplay success
一旦注册之后,所有观察者都被通知了
总结
在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。
java的swing框架中大量使用了观察者模式,很多gui框架也是如此
参考文章
《head first设计模式》