Golang 设计模式:观察者模式

使用 Golang 实现观察者模式

观察者模式介绍

观察者模式是一种行为设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

观察者模式中的角色

  1. 主题(Subject) :也称为发布者(Publisher)或可观察对象(Observable)。主题维护了一组观察者对象,并通知它们状态变化的事件。主题负责添加、删除观察者,以及通知观察者。
  2. 观察者(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开发等场景,帮助实现了更清晰、可维护的代码结构。

相关推荐
ok!ko1 小时前
设计模式之原型模式(通俗易懂--代码辅助理解【Java版】)
java·设计模式·原型模式
2401_857622661 小时前
SpringBoot框架下校园资料库的构建与优化
spring boot·后端·php
2402_857589361 小时前
“衣依”服装销售平台:Spring Boot框架的设计与实现
java·spring boot·后端
拉里小猪的迷弟2 小时前
设计模式-创建型-常用:单例模式、工厂模式、建造者模式
单例模式·设计模式·建造者模式·工厂模式
哎呦没3 小时前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端
_.Switch3 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
严文文-Chris4 小时前
【设计模式-中介者模式】
设计模式·中介者模式
刷帅耍帅4 小时前
设计模式-中介者模式
设计模式·中介者模式
杨哥带你写代码4 小时前
足球青训俱乐部管理:Spring Boot技术驱动
java·spring boot·后端
刷帅耍帅5 小时前
设计模式-组合模式
设计模式·组合模式