Golang设计模式之-观察者模式

举报
kaliarch 发表于 2022/01/29 08:17:01 2022/01/29
【摘要】 golang设计模式之观察者模式 一 观察者模式简介观察者模式是一种行为设计模式, 允许你定义一种订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象。多个对象同时观察一个对象,当这个被观察的对象发生变化的时候,这些对象都会得到通知,可以做一些操作…拥有一些值得关注的状态的对象通常被称为目标, 由于它要将自身的状态改变通知给其他对象, 我们也将其称为发布者 (publishe...

golang设计模式之观察者模式

一 观察者模式简介

观察者模式是一种行为设计模式, 允许你定义一种订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象。

多个对象同时观察一个对象,当这个被观察的对象发生变化的时候,这些对象都会得到通知,可以做一些操作…

拥有一些值得关注的状态的对象通常被称为目标, 由于它要将自身的状态改变通知给其他对象, 我们也将其称为发布者 (publisher)。 所有希望关注发布者状态变化的其他对象被称为订阅者 (subscribers)。

观察者模式建议你为发布者类添加订阅机制, 让每个对象都能订阅或取消订阅发布者事件流。 不要害怕! 这并不像听上去那么复杂。 实际上, 该机制包括 1) 一个用于存储订阅者对象引用的列表成员变量; 2) 几个用于添加或删除该列表中订阅者的公有方法。

二 代码

2.1 开发代码

package observer

import "fmt"


// 定义观察者接口
type observer interface {
    // 更新数据,发送通知
    update(string)

    // 获取具体数据对象id
    getID() string
}


// 具体观察者
type customer struct {
    id string
}

// 更新,发送email給用户
func (c *customer) update(itemName string)  {
    fmt.Printf("Sending email to customer %s for item %s\n", c.id,itemName)
}

// 获取用户id
func (c *customer) getID() string  {
    return c.id
}

// 定义被观察者, 也就是主题
type subject interface {
    register(Observer observer)
    deregister(Observer observer)
    notifyAll()
}

// 定义具体发布者被观察者主体
type item struct {
    observerList []observer
    name string
    isStock bool
}

func newItem(name string) *item {
    return &item{
        name: name,
    }
}

func (i *item) updateAvailability()  {
    fmt.Printf("Item %s is now in stock\n",i.name)
    i.isStock = true
    i.notifyAll()
}

// 注册到被观测者
func (i *item) register(o observer)  {
    i.observerList = append(i.observerList, o)
}

// 注销
func (i *item) deregister(o observer)  {
    i.observerList = removeFromslice(i.observerList, o)
}

// 通知
func (i *item) notifyAll()  {
    for _, observer := range i.observerList {
        observer.update(i.name)
    }
}

// 将一个元素从slice中移除
func removeFromslice(observerList []observer, observerToRemove observer) []observer  {
    observerListLength := len(observerList)
    for i,observer := range observerList {
        if observerToRemove.getID() == observer.getID() {
            observerList[observerListLength-1], observerList[i] = observerList[i],observerList[observerListLength-1]
            return observerList[:observerListLength-1]
        }
    }
    return observerList
}

2.2 测试

package observer

import (
    "testing"
)
func TestObserver(t *testing.T)  {
    shirtItem := newItem("nike")

    observerOne := &customer{id: "xuel"}
    observertwo := &customer{id: "wangj"}

    shirtItem.register(observerOne)
    shirtItem.register(observertwo)


    shirtItem.updateAvailability()

    shirtItem.deregister(observertwo)

    shirtItem.updateAvailability()
}

2.3 运行结果

=== RUN   TestObserver
Item nike is now in stock
Sending email to customer xuel for item nike
Sending email to customer wangj for item nike
Item nike is now in stock
Sending email to customer xuel for item nike
--- PASS: TestObserver (0.00s)
PASS

三 应用场景

当一个对象状态的改变需要改变其他对象, 或实际对象是事先未知的或动态变化的时, 可使用观察者模式。

当你使用图形用户界面类时通常会遇到一个问题。 比如, 你创建了自定义按钮类并允许客户端在按钮中注入自定义代码, 这样当用户按下按钮时就会触发这些代码。

观察者模式允许任何实现了订阅者接口的对象订阅发布者对象的事件通知。 你可在按钮中添加订阅机制, 允许客户端通过自定义订阅类注入自定义代码。

当应用中的一些对象必须观察其他对象时, 可使用该模式。 但仅能在有限时间内或特定情况下使用。

订阅列表是动态的, 因此订阅者可随时加入或离开该列表。

四 特点

4.1 优点

  • 开闭原则。 你无需修改发布者代码就能引入新的订阅者类 (如果是发布者接口则可轻松引入发布者类)。
  • 你可以在运行时建立对象之间的联系。

4.2 缺点

  • 订阅者的通知顺序是随机的。

参考链接

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

举报
请填写举报理由
0/200