鸿 网 互 联 www.68idc.cn

当前位置 : 服务器租用 > .net技术 > 控件开发 > >

【设计模式】observer(观察者)-- 对象行为型模式5.7

来源:互联网 作者:佚名 时间:2017-09-09 08:42
1.意图 对象之间一对多的 依赖关系 ,当目标对象发生 改变 时,所有依赖于它的对象都要 得到通知并自动更新 2.别名 依赖,发布-订阅 3.动机 1)需要确保相互协作的对象的 一致性 (数据要保持一致),但一致性会使各个对象 紧密耦合 ,减低它们的可重用性。

1.意图

对象之间一对多的依赖关系,当目标对象发生改变时,所有依赖于它的对象都要得到通知并自动更新

2.别名

依赖,发布-订阅

3.动机

1)需要确保相互协作的对象的一致性(数据要保持一致),但一致性会使各个对象紧密耦合,减低它们的可重用性。

2)Observer模式描述了如何建立这种关系:一个目标(Subject)可以有任意个依赖于它的观察者(Observer),当目标发生改变的时候,所有观察者都得到通知(Notify);观察者响应通知(Update),会去查询目标状态(GetState)使其状态与目标状态同步一致。

3)观察者去订阅(Subscribe),目标去发布(Publish)

4.适用性

1)一个抽象模型有两方面,一方面依赖于另一方面,两者独立封装在不同对象里以方便各自独立的改变和复用

2)一个对象的改变需要通知另一个对象,而被通知的对象数量不确定

3)被通知的对象之间互相不知道对方是谁,没有紧密耦合

5.结构 & 6.参与者

 

7.协作

8.效果

1)目标与观察者之间的抽象耦合:目标不知道具体观察者是属于哪个类的,只知道他们符合抽象Subject的接口,具体目标本身也可以是各式各样的,只要符合Object抽象接口即可,所以耦合是抽象和最小的,目标和观察者可以属于整个系统中的任意一个层次。

2)支持广播通信:目标可以无脑广播给所有它的观察者,不用知道观察者是谁,是否响应处理通知可以放在观察者层去判断

3)意外的更新:A观察者不知道B观察者的存在,A的操作导致目标改变,会通知到B,若B其实不依赖目标(定义了错误的依赖关系)可能会导致大量无效的通知或者通知导致B观察者数据错误

9.实现

1)创建目标与观察者之间的映射

  方法1:在目标里面存放观察者列表,简单,但目标多观察者少的时候存储代价会高一些

  方法2:用一个公共的对象来存储subjects 和 observers之间的映射

2)观察多个目标

  Update里面传参数Subject,来告知观察者是哪个目标更新

3)谁触发更新

  方式1:目标对象的属性变更时由目标触发更新通知,好处观察者和其他对象不用关心何时触发更新不会出现遗漏,缺点是一个操作可能会导致多次更新,也会发多次通知

  方式2:由客户来触发更新通知,好处可以随时控制触发更新时机,避免中间更新,缺点会遗漏触发

4)对已删除目标的悬挂引用

  通知目标的所有观察者把目标从身上的引用移除

5)在发出通知前确保目标的状态自身是一致的

  方式1:Subject上的Notify在SetState之后调用,因为Observer里面的Update可能会从Subject上GetState

  方式2:用Template Method模式,即父类Subject中的模板方法把重定义操作Operation()放在Notify()之前,子类只要重定义Operation方法即可,就能确保操作完了才Notify

6)通知模型 推/拉

  push推模型:把详细信息都通知给所有观察者,不管他们是否需要;推模型假定知道观察者需要什么,但假定不一定正确可能使得观察者难以复用(收到了大量无用信息,自己想要的又没有推送)

  pull拉模型只发送最小通知(如告诉观察者有更新了),观察根据自己需要从目标取他想要的数据;拉模型假定目标不知道观察者,但效率会低,因为在目标发送信息太少的情况下观察者无法知道目标到底改变了什么

7)显式的指定关心内容

  void Subject::Attach(Observer *, Aspect& interest);  观察者注册时指定关心的目标方面变更,目标只通知关心改变方面的观察者,并在Update里把Subject和Aspect都带上

  这个操作在Observer端做筛选其实也行。

8)封装复杂的更新语义

  更新管理器ChangeManager的职责,是个Mediator,Singleton

  a) 它将一个目标映射到它的观察者并提供一个接口来维护这个映射。这就不需要由目标来维护对其观察者的引用, 反之亦然。

  b) 它定义一个特定的更新策略。(比如N个目标都改变了才触发通知,或者目标在400ms发生改变只触发一次)

  c) 根据一个目标的请求, 它更新所有依赖于这个目标的观察者。

 

9)结合目标类和观察者类

  两者可以放到一个类里

10.日常开发项目应用

1)跨服逻辑,gameserver是观察者,centerserver是目标;gameserver连上后会Attach到centerserver,断开就Detach, centerserver上的globalserver列表发生更新的时候需要Notify所有的gameserver,用于更新PK服列表信息

2)战斗逻辑,player是观察者,player和monster是目标entity;entity进入player可视范围Attach,离开Detach,entity移动后坐标发生变更,需要通知他周围的观察者player坐标变更,这里使用了ChangeManager(map)来管理这个依赖关系的映射,并且制定了更新策略:发生变更不立马通知,400ms tick的时候如果有变更则通知观察者

网友评论
<