Java的API中有两组接口类是用来写观察者模式用的,分别是java.util.Observable、java.util.Observer 和java.util.EventListener、Java.util.EventObject。本文并没有直接使用到这些API,而是自定义一套观察 者模式中相关的接口类,且选取一个日常生活中常见的一个事件来说明观察者模式的使用。
现实场景:有一名店(Shop),为了财物安全起见,除了在店内装了摄像头(Camera)来监控店内的总人数外,还聘请了一些门卫(Camera)守在店门口,对来访的客人进行实名登记,即客人进入时要记名,客人出店时也要记录其离去。
//Watcher接口:
package
simple.observer;
/**
* 观察者接口
* @author rongxinhua
*
*/
public interface Watcher {
/**
* (接收到通知后,)观察者采取行动
* @param msg
*/
public void takeAction(Object msg);
}
/**
* 观察者接口
* @author rongxinhua
*
*/
public interface Watcher {
/**
* (接收到通知后,)观察者采取行动
* @param msg
*/
public void takeAction(Object msg);
}
//Watchable类:
package
simple.observer;
import java.util.HashSet;
import java.util.Set;
/**
* "被观察对象" 的父类
* @author rongxinhua
*
*/
public class Watchable {
private Set < Watcher > watcherSet = new HashSet < Watcher > ();
/**
* 通知观察者
* @param params 通知的信息数组
*/
protected void notifyWatchers(Object params) {
for (Watcher watcher : watcherSet) {
watcher.takeAction(params); // 观察者采取行动
}
}
/**
* 增加观察者
* @param watcher
*/
protected void addWatcher(Watcher watcher) {
watcherSet.add(watcher);
}
/**
* 移除观察者
* @param watcher
*/
protected void removeWatcher(Watcher watcher) {
watcherSet.remove(watcher);
}
}
import java.util.HashSet;
import java.util.Set;
/**
* "被观察对象" 的父类
* @author rongxinhua
*
*/
public class Watchable {
private Set < Watcher > watcherSet = new HashSet < Watcher > ();
/**
* 通知观察者
* @param params 通知的信息数组
*/
protected void notifyWatchers(Object params) {
for (Watcher watcher : watcherSet) {
watcher.takeAction(params); // 观察者采取行动
}
}
/**
* 增加观察者
* @param watcher
*/
protected void addWatcher(Watcher watcher) {
watcherSet.add(watcher);
}
/**
* 移除观察者
* @param watcher
*/
protected void removeWatcher(Watcher watcher) {
watcherSet.remove(watcher);
}
}
//Shop类,继承了Watchable类,Shop内有什么动静,会通过调用父类的notifyWatcher()方法通知观察者。
package
simple.observer;
import java.util.HashSet;
import java.util.Set;
/**
* 店类,可被观察的
* @author rongxinhua
*
*/
public class Shop extends Watchable {
static String IN = " in " ; // 进入
static String OUT = " out " ; // 出去
Set < String > personSet = new HashSet < String > ();
int pcount = 0 ; // 店内总人数
/**
* 来访登记
* @param name
*/
public void comeIn(String name) {
personSet.add(name);
pcount = personSet.size();
notifyWatchers(IN, name, pcount); // 通知观察者
}
/**
* 出店登记
* @param name
*/
public void getOut(String name) {
personSet.remove(name);
pcount = personSet.size();
notifyWatchers(OUT, name, pcount); // 通知观察者
}
}
import java.util.HashSet;
import java.util.Set;
/**
* 店类,可被观察的
* @author rongxinhua
*
*/
public class Shop extends Watchable {
static String IN = " in " ; // 进入
static String OUT = " out " ; // 出去
Set < String > personSet = new HashSet < String > ();
int pcount = 0 ; // 店内总人数
/**
* 来访登记
* @param name
*/
public void comeIn(String name) {
personSet.add(name);
pcount = personSet.size();
notifyWatchers(IN, name, pcount); // 通知观察者
}
/**
* 出店登记
* @param name
*/
public void getOut(String name) {
personSet.remove(name);
pcount = personSet.size();
notifyWatchers(OUT, name, pcount); // 通知观察者
}
}
//Guard(门卫类)和Camera(摄像头类)都属于本例中的观察者,负责观察店内外的动静,
package
simple.observer;
/**
* 门卫(保安)类
* @author rongxinhua
*
*/
public class Guard implements Watcher {
private String name; // 门卫姓名
public Guard() {}
public Guard(String name) {
this .name = name;
}
@Override
public void takeAction(Object msg) {
if (msg[ 0 ].equals( " in " )) {
System.out.println( this .name + " 向管理处汇报:“ " + msg[ 1 ] + " ”已进入本店! " );
}
else if (msg[ 0 ].equals( " out " )) {
System.out.println( this .name + " 向管理处汇报:“ " + msg[ 1 ] + " ”已走出本店! " );
}
}
}
/**
* 门卫(保安)类
* @author rongxinhua
*
*/
public class Guard implements Watcher {
private String name; // 门卫姓名
public Guard() {}
public Guard(String name) {
this .name = name;
}
@Override
public void takeAction(Object msg) {
if (msg[ 0 ].equals( " in " )) {
System.out.println( this .name + " 向管理处汇报:“ " + msg[ 1 ] + " ”已进入本店! " );
}
else if (msg[ 0 ].equals( " out " )) {
System.out.println( this .name + " 向管理处汇报:“ " + msg[ 1 ] + " ”已走出本店! " );
}
}
}
package
simple.observer;
/**
* 摄像头类
* @author rongxinhua
*
*/
public class Camera implements Watcher {
private int id; // 摄像头编号
public Camera( int id) {
this .id = id;
}
@Override
public void takeAction(Object msg) {
System.out.println( " 摄像头 " + id + " 号监测到现在店内总人数为 " + msg[ 2 ] + " 人 " );
}
}
/**
* 摄像头类
* @author rongxinhua
*
*/
public class Camera implements Watcher {
private int id; // 摄像头编号
public Camera( int id) {
this .id = id;
}
@Override
public void takeAction(Object msg) {
System.out.println( " 摄像头 " + id + " 号监测到现在店内总人数为 " + msg[ 2 ] + " 人 " );
}
}
//测试类代码:
package
simple.observer;
public class Test02 {
/**
* @param args
*/
public static void main(String[] args) {
Shop shop = new Shop();
// 添加摄像头1号
Camera camera = new Camera( 1 );
shop.addWatcher(camera);
// 添加门卫一号
Guard guard1 = new Guard( " 门卫一号 " );
shop.addWatcher(guard1);
// 来访登记、出门登记
shop.comeIn( " BlogJava " );
shop.comeIn( " JavaEye " );
shop.getOut( " BlogJava " );
// 移除门卫一号,派他去做别的事
shop.removeWatcher(guard1);
// 进入无人观察状态,随进随出
shop.comeIn( " CSDN " );
shop.getOut( " JavaEye " );
shop.comeIn( " 心梦帆影 " );
// 添加门卫二号
Guard guard2 = new Guard( " 门卫二号 " );
shop.addWatcher(guard2);
// 来访登记,出门登记
shop.comeIn( " 容新华 " );
shop.getOut( " CSDN " );
}
}
public class Test02 {
/**
* @param args
*/
public static void main(String[] args) {
Shop shop = new Shop();
// 添加摄像头1号
Camera camera = new Camera( 1 );
shop.addWatcher(camera);
// 添加门卫一号
Guard guard1 = new Guard( " 门卫一号 " );
shop.addWatcher(guard1);
// 来访登记、出门登记
shop.comeIn( " BlogJava " );
shop.comeIn( " JavaEye " );
shop.getOut( " BlogJava " );
// 移除门卫一号,派他去做别的事
shop.removeWatcher(guard1);
// 进入无人观察状态,随进随出
shop.comeIn( " CSDN " );
shop.getOut( " JavaEye " );
shop.comeIn( " 心梦帆影 " );
// 添加门卫二号
Guard guard2 = new Guard( " 门卫二号 " );
shop.addWatcher(guard2);
// 来访登记,出门登记
shop.comeIn( " 容新华 " );
shop.getOut( " CSDN " );
}
}
运行测试类,结果如下:
1
门卫一号向管理处汇报:“BlogJava”已进入本店!
2 摄像头1号监测到现在店内总人数为1人
3 门卫一号向管理处汇报:“JavaEye”已进入本店!
4 摄像头1号监测到现在店内总人数为2人
5 门卫一号向管理处汇报:“BlogJava”已走出本店!
6 摄像头1号监测到现在店内总人数为1人
7 摄像头1号监测到现在店内总人数为2人
8 摄像头1号监测到现在店内总人数为1人
9 摄像头1号监测到现在店内总人数为2人
10 门卫二号向管理处汇报:“容新华”已进入本店!
11 摄像头1号监测到现在店内总人数为3人
12 门卫二号向管理处汇报:“CSDN”已走出本店!
13 摄像头1号监测到现在店内总人数为2人
2 摄像头1号监测到现在店内总人数为1人
3 门卫一号向管理处汇报:“JavaEye”已进入本店!
4 摄像头1号监测到现在店内总人数为2人
5 门卫一号向管理处汇报:“BlogJava”已走出本店!
6 摄像头1号监测到现在店内总人数为1人
7 摄像头1号监测到现在店内总人数为2人
8 摄像头1号监测到现在店内总人数为1人
9 摄像头1号监测到现在店内总人数为2人
10 门卫二号向管理处汇报:“容新华”已进入本店!
11 摄像头1号监测到现在店内总人数为3人
12 门卫二号向管理处汇报:“CSDN”已走出本店!
13 摄像头1号监测到现在店内总人数为2人