finish observer pattern

This commit is contained in:
Edward 2020-05-02 21:23:04 +08:00
parent d785c6a977
commit 6082b070ed
3 changed files with 76 additions and 49 deletions

View File

@ -1,6 +1,10 @@
# 观察者模式 # 观察者模式
观察者模,又称事件订阅模式,这种模式在C#中大量存在,并且广泛应用在响应式模式中得到进一步扩展。 观察者模,又称事件订阅模式,是一种单向的消息告知模式,有事件发生了,被观察的一方告知观察的以方,一般并不要求任何回复和响应,这种模式在C#中大量存在,并且广泛应用在响应式模式中得到进一步扩展。
一个对象的改变会触发其它观察者的相关动作,当前模式实现的关键点在于被观察对象要持有观察者对象的订阅关系,否则无法通知到观察者,也就是两者一定要存在一定的关联关系,可以接口的引用,可以类型的引用/ 一个对象的改变会触发其它观察者的相关动作,当前模式实现的关键点在于被观察对象要持有观察者对象的订阅关系,否则无法通知到观察者,也就是两者一定要存在一定的关联关系,可以接口的引用,可以类型的引用.
现实生活中,网站的RSS订阅各种优惠打折的通知云服务降价促销场景都是这个模式。
通知方通过邮箱/手机等方式跟用户产生关联,当事件发生时候直接通知用户,并不要求用户响应。

View File

@ -1,47 +1,58 @@
package observer package observer
import "fmt" import (
"context"
"fmt"
)
type Subject struct { //使用RSS邮件订阅的例子
observers []Observer //某科技论坛更新时候,通过邮件通知订阅该版块的用户关注更新.
context string
type updates struct {
topic string
order int
} }
func NewSubject() *Subject { //TechBBS 科技论坛,是发送通知的主体
return &Subject{ type TechBBS struct {
observers: make([]Observer, 0), mailObservers []IMailReceiver ///邮件订阅该板块动态的用户
context context.Context ///更新的上下消息,其实就是一堆参数了
}
//IMailReceiver 邮件接收者就是订阅更新的用户
type IMailReceiver interface {
Notice(context.Context)
}
//Registry 提供给用户通过邮件注册获取/订阅更新动态的能力
func (t *TechBBS) Registry(receiver IMailReceiver) {
t.mailObservers = append(t.mailObservers, receiver)
}
//SetConext 设置更新内容的上下文
func (t *TechBBS) SetConext(ctx context.Context) {
t.context = ctx
}
//notifyUpdate 通知订阅用户,我更新了,你们可以来看了
func (t *TechBBS) noticeAllUpdate() {
for _, m := range t.mailObservers {
//逐个通知
m.Notice(t.context)
} }
} }
func (s *Subject) Attach(o Observer) { //User 用户
s.observers = append(s.observers, o) type User struct {
}
func (s *Subject) notify() {
for _, o := range s.observers {
o.Update(s)
}
}
func (s *Subject) UpdateContext(context string) {
s.context = context
s.notify()
}
type Observer interface {
Update(*Subject)
}
type Reader struct {
name string name string
} }
func NewReader(name string) *Reader { //Notice 用户收到订阅通知
return &Reader{ func (u *User) Notice(ctx context.Context) {
name: name,
}
}
func (r *Reader) Update(s *Subject) { content := ctx.Value(updates{}).(updates)
fmt.Printf("%s receive %s\n", r.name, s.context)
fmt.Printf("%s receive updates notice\n", u.name)
fmt.Printf("updates order: %d content%s\n", content.order, content.topic)
} }

View File

@ -1,17 +1,29 @@
package observer package observer
func ExampleObserver() { import (
subject := NewSubject() "context"
reader1 := NewReader("reader1") "testing"
reader2 := NewReader("reader2") )
reader3 := NewReader("reader3")
subject.Attach(reader1) func TestObserver(t *testing.T) {
subject.Attach(reader2)
subject.Attach(reader3) //内容提供商科技BBS
techInfoProvider := TechBBS{}
lily := User{"Lily"}
jacky := User{"Jacky"}
techInfoProvider.Registry(&lily)
techInfoProvider.Registry(&jacky)
updateKey := updates{}
updateValue := updates{topic: "cosmos", order: 1001}
updateContent := context.WithValue(context.Background(), updateKey, updateValue)
techInfoProvider.SetConext(updateContent)
techInfoProvider.noticeAllUpdate()
subject.UpdateContext("observer mode")
// Output:
// reader1 receive observer mode
// reader2 receive observer mode
// reader3 receive observer mode
} }