設計模式學習-使用go實現觀察者模式

Rick.lz發表於2021-11-18

觀察者模式

定義

觀察者模式(Observer Design Pattern)定義了一種一對多的依賴關係,讓多個觀察者物件同時監聽一個主題物件。這個主題物件在狀態發生變化的時,會通知所有的觀察者物件,使他們能夠更新自己。

定義物件間的一種一對多的依賴關係,當一個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新。

適用場景

1、當一個物件狀態的改變需要改變其他物件,或實際物件是事先未知的或動態變化的,可使用觀察者模式;

2、當應用中的一些物件必須觀察其他物件時,可使用該模式。但僅能在有限時間內或特定情況下使用。

優點

1、降低了目標與觀察者之間的耦合關係,兩者之間是抽象耦合關係。

2、目標與觀察者之間建立了一套觸發機制。

缺點

1、目標與觀察者之間的依賴關係並沒有完全解除,而且有可能出現迴圈引用。

2、當觀察者物件很多時,通知的釋出會花費很多時間,影響程式的效率。

程式碼實現

被觀察者有資訊更新的時候,通知到所有的觀察者。

type Subject struct {
	observers []Observer
	context   string
}

func NewSubject() *Subject {
	return &Subject{
		observers: make([]Observer, 0),
	}
}

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 Customer struct {
	name string
}

func NewCustomer(name string) *Customer {
	return &Customer{
		name: name,
	}
}

func (r *Customer) Update(s *Subject) {
	fmt.Printf("%s received %s\n", r.name, s.context)
}

測試程式碼

func TestObserver(t *testing.T) {
	subject := NewSubject()
	reader1 := NewCustomer("小明")
	reader2 := NewCustomer("小紅")
	reader3 := NewCustomer("小李")
	subject.Attach(reader1)
	subject.Attach(reader2)
	subject.Attach(reader3)

	for i := 1; i <= 10; i++ {
		subject.UpdateContext(fmt.Sprintf("更新了%d", i))
		fmt.Println("+++++++++++++++++++++++++++++++++")
	}
}

結構圖

observer

不同場景的實現方式

針對應用場景有下面四種實現方式

1、同步阻塞的實現方式;

2、非同步非阻塞的實現方式;

3、程式內的實現方式;

4、跨程式的實現方式。

慄如:可以基於訊息佇列實現

觀察模式和釋出訂閱模式

有的地方會講觀察者模式不是釋出訂閱模式

認為釋出訂閱模式相對於觀察者模式多了一個 Broker 來協調資訊的傳送者和訂閱者,而觀察模式是直接通知觀察者。

進而認為兩者的藕合程度也是不同,觀察者和被觀察者,是鬆耦合的關係,釋出者和訂閱者,則完全不存在耦合。

不過感覺者沒有明顯的區別:

觀察模式中有同步阻塞的實現方式,也有非同步非阻塞的實現方式;有程式內的實現方式,也有跨程式的實現方式。

被觀察者直接通知到觀察者這種場景就是同步阻塞的實現方式。

在被觀察者和觀察者之間加入一個訊息對列,這種方式使得兩者能夠更加的解耦,這是觀察者模式中非同步非阻塞的實現方式。

因此觀察者模式可以認為就是釋出訂閱模式,當然掌握其中的精髓,然後運用到我們的業務中才是最重要的,至於是或不是其實也沒那麼重要了。

參考

【文中程式碼】https://github.com/boilingfrog/design-pattern-learning/tree/master/觀察者模式
【大話設計模式】https://book.douban.com/subject/2334288/
【極客時間】https://time.geekbang.org/column/intro/100039001
【golang-design-pattern】https://github.com/senghoo/golang-design-pattern
【Observer vs Pub-Sub pattern】https://hackernoon.com/observer-vs-pub-sub-pattern-50d3b27f838c
【觀察者模式】https://boilingfrog.github.io/2021/11/18/使用go實現觀察者模式/

相關文章