观察者模式(Observer Pattern)的例子
Java的API中有两组接口类是用来写观察者模式用的,分别是java.util.Observable、java.util.Observer和java.util.EventListener、Java.util.EventObject。本文并没有直接使用到这些API,而是自定义一套观察者模式中相关的接口类,且选取一个日常生活中常见的一个事件来说明观察者模式的使用。
![clip_image002[13] 观察者模式(Observer Pattern)的事例](http://img.reader8.net/uploadfile/jiaocheng/20140140/2705/2014012718050413376.gif)
现实场景:有一名店(Shop),为了财物安全起见,除了在店内装了摄像头(Camera)来监控店内的总人数外,还聘请了一些门卫(Camera)守在店门口,对来访的客人进行实名登记,即客人进入时要记名,客人出店时也要记录其离去。
//Watcher接口:
package?simple.observer;
/**
?*?观察者接口
?*?@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);
????}
????
}?
//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);????//通知观察者
????}
????
}
//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]?+?"”已走出本店!");
????????}
????}
????
}?
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]?+?"人");
????}
}
//测试类代码:
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");
????????
????}
}
运行测试类,结果如下:
门卫一号向管理处汇报:“BlogJava”已进入本店!
摄像头1号监测到现在店内总人数为1人
门卫一号向管理处汇报:“JavaEye”已进入本店!
摄像头1号监测到现在店内总人数为2人
门卫一号向管理处汇报:“BlogJava”已走出本店!
摄像头1号监测到现在店内总人数为1人
摄像头1号监测到现在店内总人数为2人
摄像头1号监测到现在店内总人数为1人
摄像头1号监测到现在店内总人数为2人
门卫二号向管理处汇报:“容新华”已进入本店!
摄像头1号监测到现在店内总人数为3人
门卫二号向管理处汇报:“CSDN”已走出本店!
摄像头1号监测到现在店内总人数为2人