diff --git a/behavior/03_observer/README.md b/behavior/03_observer/README.md index b921c6e..cb6557f 100644 --- a/behavior/03_observer/README.md +++ b/behavior/03_observer/README.md @@ -1,6 +1,10 @@ # 观察者模式 -观察者模,又称事件订阅模式,这种模式在C#中大量存在,并且广泛应用。在响应式模式中得到进一步扩展。 +观察者模,又称事件订阅模式,是一种单向的消息告知模式,有事件发生了,被观察的一方告知观察的以方,一般并不要求任何回复和响应,这种模式在C#中大量存在,并且广泛应用,在响应式模式中得到进一步扩展。 -一个对象的改变会触发其它观察者的相关动作,当前模式实现的关键点在于被观察对象要持有观察者对象的订阅关系,否则无法通知到观察者,也就是两者一定要存在一定的关联关系,可以接口的引用,可以类型的引用/ +一个对象的改变会触发其它观察者的相关动作,当前模式实现的关键点在于被观察对象要持有观察者对象的订阅关系,否则无法通知到观察者,也就是两者一定要存在一定的关联关系,可以接口的引用,可以类型的引用. + +现实生活中,网站的RSS订阅,各种优惠打折的通知,云服务降价促销场景都是这个模式。 + +通知方通过邮箱/手机等方式跟用户产生关联,当事件发生时候直接通知用户,并不要求用户响应。 diff --git a/behavior/03_observer/obserser.go b/behavior/03_observer/obserser.go index 1ba4143..bddf57d 100644 --- a/behavior/03_observer/obserser.go +++ b/behavior/03_observer/obserser.go @@ -1,47 +1,58 @@ package observer -import "fmt" +import ( + "context" + "fmt" +) -type Subject struct { - observers []Observer - context string +//使用RSS邮件订阅的例子 +//某科技论坛更新时候,通过邮件通知订阅该版块的用户关注更新. + +type updates struct { + topic string + order int } -func NewSubject() *Subject { - return &Subject{ - observers: make([]Observer, 0), +//TechBBS 科技论坛,是发送通知的主体 +type TechBBS struct { + 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) { - s.observers = append(s.observers, o) -} - -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 { +//User 用户 +type User struct { name string } -func NewReader(name string) *Reader { - return &Reader{ - name: name, - } -} +//Notice 用户收到订阅通知 +func (u *User) Notice(ctx context.Context) { -func (r *Reader) Update(s *Subject) { - fmt.Printf("%s receive %s\n", r.name, s.context) + content := ctx.Value(updates{}).(updates) + + fmt.Printf("%s receive updates notice\n", u.name) + + fmt.Printf("updates order: %d content:%s\n", content.order, content.topic) } diff --git a/behavior/03_observer/obserser_test.go b/behavior/03_observer/obserser_test.go index 8b5b6e1..68f129b 100644 --- a/behavior/03_observer/obserser_test.go +++ b/behavior/03_observer/obserser_test.go @@ -1,17 +1,29 @@ package observer -func ExampleObserver() { - subject := NewSubject() - reader1 := NewReader("reader1") - reader2 := NewReader("reader2") - reader3 := NewReader("reader3") - subject.Attach(reader1) - subject.Attach(reader2) - subject.Attach(reader3) +import ( + "context" + "testing" +) + +func TestObserver(t *testing.T) { + + //内容提供商,科技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 }