1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 设计模式-观察者模式(Observer Pattern)

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

时间:2018-05-23 21:15:19

相关推荐

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

设计模式-观察者模式

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

再来看看观察者模式的定义:

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

观察者模式-类图:

背景:

英雄联盟相信大家都不陌生,WeGame助手有个常用的功能就是野怪刷新提示,只要开启这个功能,玩家在游戏里面就能收到关于野怪的刷新时间。今天就来实现以下这个功能!

分析:WeGame为玩家提供野怪刷新提示功能 (WeGame是主题,可观察者)

玩家可以在WeGame中开启此功能(注册为观察者)

下面就开始实现吧

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

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

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

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

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

/*** @author zonkidd* @create -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 -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 -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类,然后

先调用setChanged()方法,标记状态已经改变的事实。然后调用任意一种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 -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 -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 -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");}}

结果如下

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。