最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 精读《设计模式 - Observer 观察者模式》

    正文概述 掘金(黄子毅)   2021-03-01   611

    Observer(观察者模式)

    Observer(观察者模式)属于行为型模式。

    意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

    拿项目的 npm 依赖举例子:npm 包与项目是一对多的关系(一个 npm 包被多个项目使用),当 npm 包发布新版本时,如果所有依赖于它的项目都能得到通知,并自动更新这个包的版本号,那么就解决了包版本更新的问题,这就是观察者模式要解决的基本问题。

    举例子

    如果看不懂上面的意图介绍,没有关系,设计模式需要在日常工作里用起来,结合例子可以加深你的理解,下面我准备了三个例子,让你体会什么场景下会用到这种设计模式。

    对象与视图双向绑定

    在 精读《设计模式 - Proxy 代理模式》 中我们也提到了双向绑定概念,只不过代理是实现双向绑定的一个具体方案,而观察者模式才是在描述双向绑定这个概念。

    观察者模式在最初提出的时候,就举了数据与 UI 相互绑定的例子。即同一份数据可以同时渲染为表格与柱状图,那么当操作表格更新数据时,如何让柱状图的数据也刷新?从这个场景引出了对观察者模式的定义,即 “数据” 与 “UI” 是一对多的关系,我们需要一种设计模式实现当 “数据” 变化时,所有依赖于它的 “UI” 都得到通知并自动更新。

    拍卖

    拍卖由一个拍卖员与多为拍卖者组成。拍卖时,由 A 同学喊出的竞价(我出 100)就是观察者向目标发出的 setState 同时,此时拍卖员喊出(有人出价 100,还有更高的吗?)就是一个 notify 通知行为,拍卖员通知了现场竞价全员,刷新了他们对当前最高价的信息。

    聊天室

    聊天室由一个中央服务器与多个客户端组成。客户端发送消息后,就是向中央服务器发送了 setState 更新请求,此时中央服务器通知所有处于同一聊天室的客户端,更新他们的信息,从而完成一次消息的发送。

    意图解释

    数据与 UI 的例子已经详细说明了其意图含义,这里就不赘述了。

    结构图

    精读《设计模式 - Observer 观察者模式》
    • Subject: 目标,即例子中的 “数据”。
    • Observer: 观察者,即例子中的 “表格”、“柱状图”。

    还是以数据与 UI 同步为例,当表格发生操作修改数据时,表格这个 TableObserver 会调用 Subject(数据)的 setState,此时数据被更新了。然后数据这个 Subject 维护了所有监听(包括表格 TableObserver 与柱状图 ColumnChartObserver),此时 setState 内会调用 notify 遍历所有监听,并依次调用 Update 方法,每个监听的 Update 方法都会调用 getState 获取最新数据,从而实现表格更新后 -> 更新数据 -> 表格、柱状图同时刷新。

    为了更好的理解,以这张协作图为例:

    精读《设计模式 - Observer 观察者模式》
    • aConcreteSubject: 对应例子中的数据。
    • aConcreteObserver: 对应例子中的表格。
    • anotherConcreteObserver: 对应例子中的柱状图。

    代码例子

    下面例子使用 typescript 编写。

    // 目标,管理所有观察者
    class Subject {
      // 观察者数组
      private observers: Observer[] = []
      // 状态
      private state: State
    
      // 通知所有观察者
      private notify() {
        this.observers.forEach(eachObserver => {
          eachObserver.update()
        })
      }
    
      // 新增观察者
      public addObserver(observer: Observer) {
        this.observers.push(observer)
      }
    
      // 更新状态
      public setState(state: State) {
        this.state = state
        this.notify()
      }
    
      // 读取状态
      public getState() {
        return this.state
      }
    }
    
    // 观察者
    class Observer {
      // 维护目标
      private subject: Subject
    
      constructor(subject: Subject) {
        this.subject = subject
        this.subject.addObserver(this)
      }
    
      // 更新
      public update() {
        // 比如渲染表格 or 渲染柱状图
        console.log(this.subject.getState())
      }
    }
    
    // 客户端调用
    const subject = new Subject()
    // 创建观察者
    const observer1 = new Observer(subject)
    const observer2 = new Observer(subject)
    // 更新状态
    subject.setState(10)
    

    弊端

    不要拘泥于实现形式,比如上面代码中的例子,subjectobserver1observer2 是一对多的关系,但不一定非要用这种代码组织形式来实现观察者效果。我们也可以利用 Proxy 很轻松的实现:

    const obj = new Proxy(obj, {
      get(target,key) {}
      set(target,key,value) {}
    })
    
    renderTable(obj)
    renderChart(obj)
    

    我们可以在 obj 被任意一个组件访问时触发 get,进而对 UI 与视图进行绑定;被任意一个组件更新时触发 set,进而对所有使用到的视图进行刷新。使用设计模式切记不要死板,理解原理就行了,在不同平台有不同的更加优雅的实现方式。

    总结

    观察者模式是非常常用的设计模式,它描述了对象一对多依赖关系下,如何通知并更新的机制,这种机制可以用在前端的 UI 与数据映射、后端的请求与控制器映射,平台间的消息通知等大部分场景,无论现实还是程序中,存在依赖且需要通知的场景非常普遍。

    如果你想参与讨论,请 点击这里,每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。

    精读《设计模式 - Observer 观察者模式》

    起源地下载网 » 精读《设计模式 - Observer 观察者模式》

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元