观察者模式,定义了对象支架的一对多依赖,这样一来,当一个对象改变状态时,他的所有依赖者都会周到通知并自动更新。
其实就是一个数据源,其他观察值都订阅这个数据源并提供一个统一的数据更新方法供数据源数据更新的时候发送通知给各位观察者。
精髓就是所有观察者必须实现一个统一的update方法。
废话不多说了,其实理解到这个程度基本就OK了。
为了交互对象之间的松耦合设计而努力。
image.png
发个例子:气象数据变化于展示
数据源:气象数据WeatherData
观察者:气象展示CurrentDisplay
数据对象实现的接口:subject
观察者实现的接口:observer
数据展示实现的接口:displayElement
subject
//主题接口
type subject interface {
RegisterObserver(observer)
RemoveObserver(observer)
notifyObserver()
}
这里我们需要定义3个方法,注册,注销,通知
observer
//订阅者接口
type observer interface {
update(subject2 subject)
}
这里我们只需要定义一个更新数据的方法即可
displayElement
//展示接口
type displayElement interface {
Display()
}
这里我们需要定义一个公共的展示方法用于数据展示
WeatherData
//天气对象
type WeatherData struct {
subject
//温度,湿度,气压
temperature,humidity,pressure float64
observers *list.List
}
//构造函数
func NewWeatherData() *WeatherData {
instance := new(WeatherData)
instance.observers = list.New()
return instance
}
//订阅
func (this *WeatherData) RegisterObserver(observer1 observer) {
this.observers.PushBack(observer1)
}
//取消订阅
func (this *WeatherData) RemoveObserver(observer1 observer) {
for ob := this.observers.Front(); ob != nil; ob = ob.Next() {
if ob.Value.(*CurrentDisplay) == observer1.(*CurrentDisplay) {
this.observers.Remove(ob)
break
}
}
}
//通知
func (this *WeatherData) notifyObserver() {
for ob := this.observers.Front(); nil != ob; ob = ob.Next() {
ob.Value.(observer).update(this)
}
}
//信息更新方法
func (this *WeatherData) SetMeasurements(temperature float64,humidity float64,pressure float64) {
this.temperature = temperature
this.humidity = humidity
this.pressure = pressure
this.notifyObserver()
}
数据对象,除了数据属性,还有subject的方法,我们还需要一个更新数据的方法
CurrentDisplay
//当前气象
type CurrentDisplay struct {
observer
displayElement
temperature,humidity,pressure float64
}
//更新
func (this *CurrentDisplay)update(subject2 subject) {
this.temperature = subject2.(*WeatherData).temperature
this.humidity = subject2.(*WeatherData).humidity
this.pressure = subject2.(*WeatherData).pressure
this.Display()
}
//信息展示
func (this *CurrentDisplay)Display() {
fmt.Println("当前气温:" + strconv.FormatFloat(this.temperature, 'f',2,64))
fmt.Println("当前湿度:" + strconv.FormatFloat(this.humidity, 'f',2,64))
fmt.Println("当前气压:" + strconv.FormatFloat(this.pressure, 'f',2,64))
}
当前气象展示,实现update和Display接口
一切都准备好了,我们主函数测试下,这里为了省事只写了一个CurrentDisplay的观察者,实际上我们还可以定义很多,比如最高气温,平均气温等等。
为了看效果,主函数里初始化了两个CurrentDisplay,这样可以看出订阅和取消的效果
func main() {
//气象信息
weatherData := observerPattern.NewWeatherData()
//当前气象1
currentDisplay1 := new(observerPattern.CurrentDisplay)
weatherData.RegisterObserver(currentDisplay1)
//更新气象信息
println("第一次气象信息更新")
weatherData.SetMeasurements(30.23,24.01,36.52)
//当前气象2
currentDisplay2 := new(observerPattern.CurrentDisplay)
weatherData.RegisterObserver(currentDisplay2)
//更新气象信息
println("第二次气象信息更新")
weatherData.SetMeasurements(29.96,23.64,37.01)
//currentDisplay1取消订阅weatherData
weatherData.RemoveObserver(currentDisplay1)
//更新气象信息
println("第三次气象信息更新")
weatherData.SetMeasurements(31.11,25.65,37.25)
}
执行以下,结果:
第一次气象信息更新
当前气温:30.23
当前湿度:24.01
当前气压:36.52
第二次气象信息更新
当前气温:29.96
当前湿度:23.64
当前气压:37.01
当前气温:29.96
当前湿度:23.64
当前气压:37.01
第三次气象信息更新
当前气温:31.11
当前湿度:25.65
当前气压:37.25