go 设计模式- 观察者模式

120 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情

众多对象之间的一对多关系是这种观察者模式的基础。 它使您能够设置订阅机制,允许其他实体在您订阅的实体上的每次事件时收到警报。Kafka、RabbitMQ、Amazon SNS 和 NATS 是实现发布者/订阅者模式(观察者的一种变体!)的发布/订阅系统的一些真实示例。

应用场景

  • 在 Web 开发领域,尤其是使用 React,您听说过 Redux 用于管理应用程序的状态。 Redux 是观察者模式的实现。当你附加一个动作来更新 store 中的状态时,监听变化的组件会相应地调整它们的表示。
  • 如果代码被贡献到远程存储库,CI 环境将监视它的更改并执行构建。
  • 事件驱动的过程式编程用于模仿观察者设计模式。

与其他设计模式一样,这种模式允许我们定义松散链接的系统。 我们可以使用这种技术开发可维护的模块化软件。 我们还可以在事件驱动系统中实现不同参与者之间的明显分割。

组成

  • 抽象被观察者:抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
  • 具体被观察者:具体目标类,实现抽象中的通知方法,变更时调用观察者。
  • 抽象观察者 :定义接口,包含更新自己的抽象方法,当接到具体被观察者的变化通知时被调用
  • 具体观察者:实现抽象观察者的方法,这样观察到变化时进行变更自身

代码实现

// 抽象观察者
type IObserver interface {
	Change(sub *Subject)
}

// 具体被观察对象(主体)
type Subject struct {
	observers []IObserver
	name      string
}

// 添加观察者
func (s *Subject) AddObserver(o IObserver) {
	s.observers = append(s.observers, o)
}

// 通知信息到观察者
func (s *Subject) Notify() {
	for _, o := range s.observers {
		o.Change(s)
	}
}

// 被观察者发生变更时
func (s Subject) ChangeName(name string) {
	s.name = name
	s.Notify()
}

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

// 具体观察者
type Receiver struct {
	name string
}

func (r *Receiver) Change(s *Subject) {
	fmt.Printf("[%s] 接收到: %v\n",
		r.name, s.name)
}

func NewRecevier(name string) *Receiver {
	return &Receiver{name}
}

func main() {
	sub := NewSubject()
	r1 := NewRecevier("AAA")
	r2 := NewRecevier("BBB")
	r3 := NewRecevier("CCC")

	sub.AddObserver(r1)
	sub.AddObserver(r2)
	sub.AddObserver(r3)
	sub.ChangeName("名字")

}

被观察者就是主题,有三个方法:添加观察者,发生变更,通知观察者;观察者一个方法:接收主体的通知。这样无论主题多少个或者发生什么变更,只需要在变更时调用自己的通知方法。而通知方法就是观察者的接收的方法。符合开闭原则,易于扩展。且只有在运行时才建立对象之间的联系