使用 Golang 实现观察者模式
观察者模式介绍
观察者模式是一种行为设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
观察者模式中的角色
- 主题(Subject) :也称为发布者(Publisher)或可观察对象(Observable)。主题维护了一组观察者对象,并通知它们状态变化的事件。主题负责添加、删除观察者,以及通知观察者。
- 观察者(Observer) :也称为订阅者(Subscriber)。观察者是主题状态的依赖者,它定义了一个通知方法,当主题状态发生变化时,该方法会被调用。观察者模式允许任意数量的观察者订阅一个主题,而主题无需知道观察者的具体是谁。
场景
在生活中,随时随地可以找到观察者模式的例子;例如我们想要订阅新闻,可以通过新闻系统订阅感兴趣的新闻类别来接收相应的新闻通知。在这个场景中,我们就是角色中的观察者(订阅者),新闻系统是角色中的发布者,新闻系统中的某一类别的新闻是具体的发布者。具体如图所示
代码示例说明
以下是一个简单的 Golang 代码示例,以上述的新闻系统为例子,演示观察者模式:
Publisher(发布者)接口
go
type Publisher interface {
register(subscriber Subscriber)
deRegister(subscriber Subscriber)
notifyAll()
}
NewsPublisher(新闻发布者)结构体
go
type NewsPublisher struct {
subscriberList []Subscriber
category string
newsNum int64
}
func NewNewsPublisher(category string, newsNum int64) *NewsPublisher {
return &NewsPublisher{category: category, newsNum: newsNum}
}
// 实现订阅者注册
func (np *NewsPublisher) register(s Subscriber) {
np.subscriberList = append(np.subscriberList, s)
}
// 取消订阅
func (np *NewsPublisher) deRegister(s Subscriber) {
np.subscriberList = remove(np.subscriberList, s)
}
// 通知
func (np *NewsPublisher) notifyAll() {
fmt.Printf("%d %s News has been released\n", np.newsNum, np.category)
for _, subscriber := range np.subscriberList {
subscriber.update(np.newsNum, np.category)
}
}
// 移除元素
func remove(subList []Subscriber, removeSub Subscriber) []Subscriber {
subListLength := len(subList)
for i, subscriber := range subList {
//fmt.Println("=========="+removeSub.getName() == subscriber.getName())
if removeSub.getName() == subscriber.getName() {
// 与最后一个交换位置 直接移除最后一个 避免新切片创建 不涉及大规模元素移动
subList[subListLength-1], subList[i] = subList[i], subList[subListLength-1]
return subList[:subListLength-1]
}
}
return subList
}
Subscriber(订阅者)接口
go
type Subscriber interface {
update(int64, string)
getName() string
}
User(具体订阅者)结构体
go
type User struct {
name string
}
func (u *User) getName() string {
return u.name
}
func (u *User) update(newsNum int64, subCategory string) {
fmt.Printf("Sending %d %s News to %s\n", newsNum, subCategory, u.name)
}
主程序
go
func main() {
// 创建Sports新闻发布者
sportsNewsPublisher := NewNewsPublisher("Sports", 2)
// 创建两个订阅者
subscriber1 := &User{name: "张三"}
subscriber2 := &User{name: "李四"}
// 订阅Sports新闻
sportsNewsPublisher.register(subscriber1)
sportsNewsPublisher.register(subscriber2)
// 发布Sports新闻并通知订阅者
sportsNewsPublisher.notifyAll()
// 创建International新闻发布者
internationalNewsPublisher := NewNewsPublisher("International", 1)
// 创建两个订阅者
subscriber3 := &User{name: "张三"}
subscriber4 := &User{name: "李四"}
// 订阅International新闻
internationalNewsPublisher.register(subscriber3)
internationalNewsPublisher.register(subscriber4)
// 发布International新闻并通知订阅者
internationalNewsPublisher.notifyAll()
}
输出
css
2 Sports News has been released
Sending 2 Sports News to 张三
Sending 2 Sports News to 李四
1 International News has been released
Sending 1 International News to 张三
Sending 1 International News to 李四
上述代码中,NewsPublisher
充当发布者的角色,而 User
则充当订阅者的角色。通过 register
方法,订阅者可以订阅感兴趣的新闻类别,而通过 notifyAll
方法,发布者在发布新闻时通知所有订阅者进行更新。
总结
观察者模式通过松耦合的设计,使得发布者和订阅者可以独立演化,增强了系统的灵活性。在实际应用中,观察者模式被广泛应用于事件处理、UI开发等场景,帮助实现了更清晰、可维护的代码结构。