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开发等场景,帮助实现了更清晰、可维护的代码结构。

相关推荐
2401_857600953 小时前
电商系统开发:Spring Boot框架实战
java·spring boot·后端
她说人狗殊途5 小时前
设计模式学习
java·学习·设计模式
天草二十六_简村人5 小时前
spring-data-elasticsearch 3.2.4 实现桶bucket排序去重,实现指定字段的聚合搜索
java·spring boot·后端·spring·elasticsearch·架构·jenkins
拔剑纵狂歌6 小时前
ZooKeeper单机、集群模式搭建教程
分布式·后端·学习·zookeeper·中间件·架构·服务发现
jokerest1236 小时前
web——upload-labs——第五关——大小写绕过绕过
前端·后端
java_python源码6 小时前
[含文档+PPT+源码等]精品基于springboot实现的原生Andriod手机使用管理软件
java·spring boot·后端
技术猿188702783518 小时前
Spring Boot应用中的文件压缩与解压技术实践
java·spring boot·后端
码哥字节8 小时前
30+ 程序员降薪跳槽到银行,技术优势成了空谈。银行的职场环境,远比想象中的要复杂
后端
hlsd#8 小时前
go 集成swagger 在线接口文档
开发语言·后端·golang
大脑经常闹风暴@小猿8 小时前
Django 启用国际化支持—实现配置多国语言
后端·python·django