设计模式-观察者模式(Observer Pattern)

设计模式-观察者模式

观察者模式是使用频率最高的设计模式之一,它用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应作出反应。在观察者模式中,发生改变的对象称为观察目标(主题),而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间可以没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。
再来看看观察者模式的定义:

观察者模式(Observer Pattern):在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。

观察者模式-类图:
在这里插入图片描述

背景:
英雄联盟相信大家都不陌生,WeGame助手有个常用的功能就是野怪刷新提示,只要开启这个功能,玩家在游戏里面就能收到关于野怪的刷新时间。今天就来实现以下这个功能!
分析:WeGame为玩家提供野怪刷新提示功能 (WeGame是主题,可观察者)
   玩家可以在WeGame中开启此功能(注册为观察者)

在这里插入图片描述
下面就开始实现吧

定义一个Subject (主题、可观察者)接口


/**
 * @author zonkidd
 * @create 2019-01-31 
 */
public interface Subject {
    public void registerObserver(Observer o);	//注册Observer对象为观察者
    public void removeObserver(Observer o);		//移除观察者
    public void notifyObserver();				//通知所有观察者

}

定义一个Observer (观察者)接口


/**
 * @author zonkidd
 * @create 2019-01-31 
 */
public interface Observer {
    public void update(String buff,String time);	

}

定义一个具体WeGame类实现Subject接口


/**
 * @author zonkidd
 * @create 2019-01-31 
 */
import java.util.ArrayList;

public class WeGame implements Subject{
    private ArrayList observers;	//记录观察者

    private String buff=null;
    private String time=null;


    public WeGame(){
        observers=new ArrayList (  );
    }
    public void registerObserver(Observer o){ //想要注册为观察者,调用此方法即可
        observers.add ( o );
    }

    public void removeObserver(Observer o){//同样地,当观察者想取消注册,可调用这个方法
        int i=observers.indexOf ( o );
        if(i >=0)
            observers.remove ( i );
    }
    public void notifyObserver(){	/*在这里,我们将把状态告诉每一个观察者,因为每个观察者  
    								都实现了update(),所以可以通过这个方法通知它们。*/
        for (int i = 0; i <observers.size () ; i++) {
            Observer observer=(Observer) observers.get ( i ); //获得Observer对象
            observer.update (buff,time);
        }

    }
    public void neutralsChanged(){	//当获得野怪更新的状态,我们通知观察者
        notifyObserver ();
    }

    public void setNeutrals(String buff,String time)
        {
            this.buff=buff;
            this.time=time;
            neutralsChanged ();
        }
}

我们已经把WeGame类写出来了,现在该轮到Player类(观察者)。假设有三个玩家开启了该功能


/**
 * @author zonkidd
 * @create 2019-01-31 
 */
public class Player1 implements Observer{
        private String buff=null;
        private String time=null;
        private Subject weGame;
        
        public Player1(Subject weGame){
            this.weGame=weGame;
            weGame.registerObserver ( this ); //注册该对象为观察者
        }
        
        public void update(String buff,String time){
            this.buff=buff;
            this.time=time;
            display();
        }
        
        public void display(){
            System.out.println("player1:收到:"+buff+"将于"+time+"s之后刷新");
        }
}

Player2和Player3 省略,因为与Player1基本一样。

建立一个测试程序 WeGameMain


/**
* @author zonkidd
* @create 2019-01-31 
*/
public class WeGameMain {

  public static void main(String[] args){
     WeGame weGame=new WeGame ();
     Player1 player1=new Player1 ( weGame );
     Player2 player2=new Player2 ( weGame );
     Player3 player3=new Player3 ( weGame );

      //接下来可以调用一个野怪状态更新的方法,看下Player1,Player2,Player3会不会收到
      weGame.setNeutrals ( "红BUFF","20" );
      weGame.setNeutrals ( "蓝BUFF","25" );

  }
}

结束显示:
在这里插入图片描述

使用Java内置的观察模式 来实现

类图:
在这里插入图片描述
Java内置的观察者模式如何运作
和我们上面所实现的有所类似,但有一些小差异,最明显的是WeGame现在扩展自Observable类,并继承到一些增加、删除、通知观察者的方法(以及其他方法)、

如何把对象变成观察者…

实现观察者接口(java.util.Observer),然后调用任何Observable对象的addObserver()方法。不想再当观察者时,调用deleteObserver()方法即可。

观察者要如何送出通知

先继承java.util.Observable类,然后

  1. 先调用setChanged()方法,标记状态已经改变的事实。
  2. 然后调用任意一种notifyObserver()方法
    notifyObserver( ) 或 notifyObserver( Object arg )

setChanged()存在的意义:

	//Observable类的源码

  protected synchronized void setChanged() {
      changed = true;
 	 }
 	 
  public void notifyObservers(Object arg) {
      /*
       * a temporary array buffer, used as a snapshot of the state of
       * current Observers.
       */
      Object[] arrLocal;

      synchronized (this) {
          /* We don't want the Observer doing callbacks into
           * arbitrary code while holding its own Monitor.
           * The code where we extract each Observable from
           * the Vector and store the state of the Observer
           * needs synchronization, but notifying observers
           * does not (should not).  The worst result of any
           * potential race-condition here is that:
           * 1) a newly-added Observer will miss a
           *   notification in progress
           * 2) a recently unregistered Observer will be
           *   wrongly notified when it doesn't care
           */
          if (!changed)  		
              return;
          arrLocal = obs.toArray();
          clearChanged();
      }

      for (int i = arrLocal.length-1; i>=0; i--)
          ((Observer)arrLocal[i]).update(this, arg);
  }

当changed值为false时,跳出方法,不在执行下去
这样做有其必要性,setChanged()方法可以让你在更新观察者时,有更多的弹性,你可以更适当地通知观察者,比方说,如果没有setChanged()方法,WeGame的野怪时间计算可能每减少一秒就更新一次,这会造成WeGame(主题对象)持续不断地通知观察者,这样并不是我们想要的。如果我们希望在野怪还有20秒刷新时才更新,就可以在距离野怪刷新20秒才调用setChanged()方法,进行有效的更新。

观察者如何接收通知

update( Observable o, Object arg )

如果你想“推”(push)数据给观察者,就可以调用notifyObserver( Object arg ) ,
否则 观察者就必须从可观察者对象中“拉”(pull)数据。

WeGame改成继承Observable

import java.util.Observable;

/**
 * @author zonkidd
 * @create 2019-01-31 
 */
public class WeGame extends Observable {
    private String buff=null;
    private String time=null;
    public WeGame(){}

    public void neutralsChanged(){
        setChanged ();
        notifyObservers (); /*注意:我们没有调用notifyObservers (arg) 传送数据对象  
        						,这表示我们采用的做法是 "拉"*/
    }

    public void setMeasurements(String buff,String time){
        this.buff=buff;
        this.time=time;
        neutralsChanged ();
    }

    public String getBuff() {
        return buff;
    }

    public String getTime() {
        return time;
    }

}

定义 Player(观察者) 实现 Observer接口


import java.util.Observable;
import java.util.Observer;

/**
 * @author zonkidd
 * @create 2019-01-31 
 */
public class Player1 implements Observer {
        Observable observer;
        private String buff=null;
        private String time=null;
    public Player1(Observable observable)
    {
        this.observer=observable;
        observable.addObserver ( this );	//注册为观察者
    }

    public void update(Observable observable,Object arg){
        if(observable instanceof WeGame){
            WeGame weGame= (WeGame) observable	//向下转型;
           
            buff=weGame.getBuff();
            time=weGame.getTime ();
            display();

        }
    }

    private void display() {
        System.out.println("player1:收到:"+buff+"将于"+time+"s之后刷新");
    }
}

Player2和Player3 省略

执行类WeGameMain


/**
* @author zonkidd
* @create 2019-01-31
*/
public class WeGameMain {
   public static void main(String[] args) {
       WeGame weGame=new WeGame ();

       Player1 player1=new Player1 ( weGame ); //player1开启此功能
       Player2 player2=new Player2 ( weGame ); //player2开启此功能
       Player3 player3=new Player3 ( weGame ); //player3开启此功能

       //经过一系列 运算,省略,weGame得到了野怪准备要刷新的内幕消息
       // 调用野怪状态更新的方法
       weGame.setNeutrals("红buff","20");
       weGame.setNeutrals ("蓝buff","40");
   }

}

结果如下
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值