设计模式学习笔记之-Observer模式

1           意图

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

 

2           别名

依赖(Dependents, 发布-订阅(Publish-Subscribe

 

3           动机

将一个系统分割成一系列相互协作的类有一个常见的副作用,需要维护相关对象间的一致性,我们不希望为此而使得各个类紧密耦合,因为这样降低了他们的可重用性。

Observer模式描述了如何建立这种关系,这一模式中的关键对象是目标(subject)和观察着(observer),一个目标可以有任意数目的依赖它的观察者。一旦目标的状态发生改变,所有的观察着都得到通知,作为对这个通知的响应,每个观察着都将查询目标以使其状态与目标的状态同步。这种交互也称为发布-订阅,目标是通知的发布者,它发出通知时病不需要知道谁是它的观察者,可以有任意数目的观察者订阅并接收通知

 

4           适用性

4.1          当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两者封装在独立的对象中使他们可以各自独立的改变和复用

4.2          当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变

4.3          当一个对象必须通知其他对象,而它不能假定其他对象是谁,换而言之,你不希望这些对象是紧密耦合的

 

5           结构

 

6           交互

 

 

7           效果

7.1          优点

7.1.1     目标和观察者之间的抽象耦合

7.1.2     支持广播通信

7.2          缺点

意外的更新:如果依赖准则的定义或维护不当,常常会引起错误的更新,这种错误是很难捕捉的。

 

8           实现

8.1          创建目标到其观察者之间的映射

8.1.1     显式的在目标中保存对他们的引用

8.1.2     时间换空间,用一个关联查找机制(例如hash表)来维护目标到观察者的映射

8.2          观察多个目标

扩展Update接口,以使观察者知道哪个目标送来的通知,目标对象可以简单的将自己作为Update操作的一个参数,让观察者知道该去检查哪一个目标

8.3          谁触发谁更新

8.3.1     由目标对象的状态设定操作在改变目标对象的状态后自动调用Notify

8.3.1.1    优点:客户不需要记住要在目标对象上调用Notify

8.3.1.2    缺点:多个连续的操作会产生多次连续的更新,可能效率较低

8.3.2     让客户负责在适当的时候调用Notify

8.3.2.1    优点:客户可以在一系列状态改变完成后再一次性的触发更新,避免了不必要的中间更新

8.3.2.2    缺点:客户增加了触发更新的责任,客户可能忽而忘记调用Notify

8.4          对已经删除的目标的悬挂引用

8.4.1     当一个目标被删除时,让它通知它的观察者将对该目标的引用复位

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

在文档中记录哪一个subject操作触发通知总是应该的

8.6          避免特定于观察者的更新协议/拉模型

8.6.1     推模式:目标向观察者发送关于改变的详细信息,而不管它们需要与否。假定目标知道一些观察者需要的信息。可能使得观察者相对难以复用,因为目标对观察者的假定可能并不总是正确的。

8.6.2     拉模式:目标除了最小通知外什么也不送出,在此后由观察者显示的向目标询问细节。强调目标不知道她的观察者。可能效率较差,因为观察者对象需在没有目标对象帮助的情况下确定什么改变了

8.7          显示指定感兴趣的改变

8.7.1     扩展目标的注册接口,让各观察者注册为仅对特定事件感兴趣,以提高更新的效率。当一个事件发生时候,目标仅仅通知那些已注册为对该事件感兴趣的观察者。支持这种做法的一种途径,对使用目标对象的方面(aspects)的概念。可用下面代码将观察者对象注册为对目标对象的某特定事件感兴趣:

       void Subject::Attach(Observer * , Aspect & interest)

     通知时候,目标将这方面的改变作为Update操作的一个参数提供给他的观察者

       void Observer::Update(Subject * ,Aspect & interest)

8.8          封装复杂的更新语义

     更改管理器(ChangeManager):目的是尽量减少观察者反映其目标的状态变化所需的工作量,例如,如果一个操作涉及对几个相互依赖的目标进行改动,就必须保证仅仅在所有的目标都已经更改完毕后,才一次性的通知他们的观察者,而不是每个目标都通知观察者

     ChangeManager的三个职责:

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

8.8.2     定义一个特定的更新策略

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

9           相关模式

9.1          Mediator :通过封装复杂的更新语义,ChangeManager充当目标和观察者之间的中介者

9.2          Singleton ChangeManager可使用Singleton模式来保证它是唯一的并且是可全局访问的

10       JDK中的ObserverObservable

    一个 observable 对象可以有一个或多个观察者。观察者可以是实现了 Observer 接口的任意对象。一个 observable 实例改变后,调用 Observable notifyObservers 方法的应用程序会通过调用观察者的 update 方法来通知观察者该实例发生了改变。

未指定发送通知的顺序。Observable 类中所提供的默认实现将按照其注册的重要性顺序来通知 Observers,但是子类可能改变此顺序,从而使用非固定顺序在单独的线程上发送通知,或者也可能保证其子类遵从其所选择的顺序。

注意,此通知机制与线程无关,并且与 Object 类的 wait notify 机制完全独立。

Observable的方法摘要:

void

addObserver(Observer o)
          
如果观察者与集合中已有的观察者不同,则向对象的观察者集中添加此观察者。

protected  void

clearChanged()
          
指示对象不再改变,或者它已对其所有的观察者通知了最近的改变,所以 hasChanged 方法将返回 false

 int

countObservers()
          
返回 Observable 对象的观察者数目。

 void

deleteObserver(Observer o)
          
从对象的观察者集合中删除某个观察者。

 void

deleteObservers()
          
清除观察者列表,使此对象不再有任何观察者。

 boolean

hasChanged()
          
测试对象是否改变。

 void

notifyObservers()
          
如果 hasChanged 方法指示对象已改变,则通知其所有观察者,并调用 clearChanged 方法来指示此对象不再改变。

 void

notifyObservers(Object arg)
          
如果 hasChanged 方法指示对象已改变,则通知其所有观察者,并调用 clearChanged 方法来指示此对象不再改变。

protected  void

setChanged()
          
标记此 Observable 对象为已改变的对象;现在 hasChanged 方法将返回 true

11       最简单的Observable实现:

 

package mvc.mobile.util;

 

/**

 * <p>Title: </p>

 *

 * <p>Description:Observer interface for j2me</p>

 *

 * <p>Copyright: Copyright (c) 2009</p>

 *

 * <p>Company: </p>

 *

 * @author not attributable

 * @version 1.0

 */

public interface Observer {

  void update(Observable iTarget, Object iInterests);

}

package mvc.mobile.util;

 

import java.util.Vector;

 

/**

 * <p>Title: </p>

 *

 * <p>Description: 最简单的Observable实现</p>

 *

 * <p>Copyright: Copyright (c) 2009</p>

 *

 * <p>Company: </p>

 *

 * @author not attributable

 * @version 1.0

 */

public class Observable {

  private boolean iChanged = false;

  private Vector iObs ;

  public Observable() {

    //创建目标时候就新建一个观察者列表,注意这个列表需要同步

    iObs = new Vector();

  }

  /**

   * 添加观察者到观察者列表中

   */

  public synchronized void addObserver(Observer aObserver){

    if(aObserver == null )

      return ;

    if(!iObs.contains(aObserver))

    iObs.addElement(aObserver);

  }

  /**

   * 删除一个观察者

   */

  public synchronized void deleteObserver(Observer aObserver){

   iObs.removeElement(aObserver);

  }

  /**

   * 通知操作,即被观察者发生变化,通知对应的观察者进行事先设定的操作,不传参数的通知方法

   */

  public void notifyObserver(){

   notifyObservers(null);

  }

  public void notifyObservers(Object aArg){

 

   synchronized(this){

     if(!iChanged)

        return ;

      clearChanged();

   }

   for(int i= iObs.size()-1; i>=0 ;i--)

     ((Observer)iObs.elementAt(i)).update(this,aArg);

  }

  protected synchronized void clearChanged(){

    iChanged = false;

  }

  protected synchronized void setChanged(){

    iChanged = true ;

  }

  public static void main(String[] args) {

    Observable observable = new Observable();

 

  }

}

测试用例:

package mvc.mobile.test.observerTest;

import mvc.mobile.util.Observer;

import mvc.mobile.util.Observable;

 

/**

 * <p>Title: </p>

 *

 * <p>Description: </p>

 *

 * <p>Copyright: Copyright (c) 2009</p>

 *

 * <p>Company: </p>

 *

 * @author not attributable

 * @version 1.0

 */

public class Friend  implements Observer{

  private String iName ;

  public String getName() {

    return iName;

  }

  public void setName(String aName){

    iName = aName ;

  }

  public Friend(String aName) {

     iName  =aName ;

  }

 

  public void update(Observable iTarget, Object iInterests) {

    if(iInterests instanceof Long)

      System.out.println(iName+"已经知道你的手机号码改变为:"+iInterests);

   

  }

}

 

 

package mvc.mobile.test.observerTest;

 

import mvc.mobile.util.Observable;

 

/**

 * <p>Title: </p>

 *

 * <p>Description: </p>

 *

 * <p>Copyright: Copyright (c) 2009</p>

 *

 * <p>Company: </p>

 *

 * @author not attributable

 * @version 1.0

 */

public class ModifyPhoneNum extends Observable{

  public ModifyPhoneNum() {

    super();

    addFriend(new Friend("李培"));

    addFriend(new Friend("晓红"));

   

  }

  public void addFriend(Friend aFriend){

     super.addObserver(aFriend);

  }

  /**

   * 手机号改变,通知好友

   */  

  public void modifyPhoneNum(final Long iPhoneNum){

      /**

       * 表明状态已经改变,不调用的话,不会通知观察者

       */

      setChanged();

      //通知其他好友自己的电话号码改变了

      notifyObservers(iPhoneNum);

      }

 

  public static void main(String[] args) {

    ModifyPhoneNum modifyphonenum = new ModifyPhoneNum();

    modifyphonenum.modifyPhoneNum(new Long(123456789));

  }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值