观察者模式在JDK中有了很好的支持,目前,开发者使用JDK提供的观察者模式有两种途径。
1. 被观察者继承Observerable父类;观察者实现Oberver接口。
2. 在EventObject中封装消息参数;然后,在EventListenr中实现监听者(观察者)的动作。
首先来看采用Observable实现的观察者模式。
在这个例子中,我们将以“北朝鲜”作为一个被观察者,而北朝鲜的一举一动都影响的着半岛的稳定。而中美作为世界的两个大国,更是时刻关注者北朝鲜的一举一动。因此,中国和美国,各自都是观察者。而北朝鲜的关注点,无非是“原子弹”和“金正日同志的健康”。因此,如果,朝鲜宣布,核爆成功,那么,这两个观察者就会分别发表声明;如果,金正日死了,那么,两个观察者在观察到这个消息之后,也会做出不同的表态。
封装了半岛局势的枚举:
/**
* 朝鲜半岛的关注点。
*
* @author hongxin.xu
* @version $Id: PeninsulaEnum.java, v 0.1 2012-1-2 下午3:46:10 hongxin.xu Exp $
*/
public enum PeninsulaEnum {
/** 试爆成功。 */
NUCLEAR,
/** 金哥Bye! */
KIMJIONIIDEAD;
}
被观察者(北朝鲜的实例),这里需要注意的是,被观察者,必须要继承Observable父类。该父类中提供了“添加监听器”、“删除监听器”、“触发监听器”的方法。注意,在触发监听器操作之前,必须设置变更状态。否则,监听器将不会被触发。
/**
* 被观察者的实例。
* <p>
* 伟大的北朝鲜政权,是世界各国关注的焦点。 因此,在这里将其作为一个被观察者的实例。
* </p>
*
* @author hongxin.xu
* @version $Id: ChinaObserver.java, v 0.1 2012-1-2 下午3:14:53 hongxin.xu Exp $
*/
public class NorthKoreaSubject extends Observable {
public static void main(String[] args) {
// 声明两个观察者。
Observer china = new ChinaObserver();
Observer american = new AmericanObserver();
// 添加观察者
NorthKoreaSubject northKoreaSubject = new NorthKoreaSubject();
northKoreaSubject.addObserver(china);
northKoreaSubject.addObserver(american);
// 触发事件。
System.out.println("Kim-Jong-II:我们有原子弹了思密达!");
northKoreaSubject.setPeninsulaEnum(PeninsulaEnum.NUCLEAR);
// 触发事件。
System.out.println("Kim-Jong-II:我挂了~~~");
northKoreaSubject.setPeninsulaEnum(PeninsulaEnum.KIMJIONIIDEAD);
}
/**
* @param peninsulaEnum
* the peninsulaEnum to set
*/
public void setPeninsulaEnum(PeninsulaEnum peninsulaEnum) {
// 设置状态位。
super.setChanged();
// 触发notify事件。
super.notifyObservers(peninsulaEnum);
}
}
下面给出两个观察者的实例:
1.中国
/**
* 中国作为一个观察者,时时刻刻关注着北朝鲜的动态。
*
* @author hongxin.xu
* @version $Id: ChinaObserver.java, v 0.1 2012-1-2 下午3:19:39 hongxin.xu Exp $
*/
public class ChinaObserver implements Observer {
/**
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
@Override
public void update(Observable o, Object arg) {
if (arg instanceof PeninsulaEnum) {
PeninsulaEnum msg = (PeninsulaEnum) arg;
if (msg == PeninsulaEnum.KIMJIONIIDEAD) {
System.out.println(" --中国外交部发来唁电");
}
if (msg == PeninsulaEnum.NUCLEAR) {
System.out.println(" --中国外交部表示谴责!");
}
}
}
}
2.美国
public class AmericanObserver implements Observer {
/**
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
@Override
public void update(Observable o, Object arg) {
if (arg instanceof PeninsulaEnum) {
PeninsulaEnum msg = (PeninsulaEnum) arg;
if (msg == PeninsulaEnum.KIMJIONIIDEAD) {
System.out.println(" --白宫表示毫无压力");
}
if (msg == PeninsulaEnum.NUCLEAR) {
System.out.println(" --白宫很生气,后果很严重");
}
}
}
}
至此,我们就利用Observable实现了一个观察者模式。其运行的结果为:
Kim-Jong-II:我们有核原子弹了思密达!
--白宫很生气,后果很严重
--中国外交部表示谴责!
Kim-Jong-II:我挂了~~~
--白宫表示毫无压力
--中国外交部发来唁电
以上是采用Observer/Observerable实现的观察者模式。在JDK中还有另外的一种,实现观察者模式的方法,那就是使用EventObject和EventListener。还是采用“北朝鲜”的例子,我们来进行说明:
首先,定义半岛局势的枚举
/**
* 定义半岛局势的枚举
*
* @author ibm
*
*/
public enum PeninsulaEnum {
UNCLEAN, KIMJIONIIDEAD;
}
然后,在PeninsulaSituation中封装对该枚举的引用。同时,实现的状态的设置。
/**
* 半岛局势实例。
*
* @author ibm
*
*/
public class PeninsulaSituation extends EventObject {
/**
*
*/
private static final long serialVersionUID = 1L;
/** 半岛枚举。 */
private PeninsulaEnum peninsulaEnum;
public PeninsulaSituation(Object source) {
super(source);
// TODO Auto-generated constructor stub
if (source instanceof PeninsulaEnum) {
peninsulaEnum = (PeninsulaEnum) source;
}
}
/**
* @return the peninsulaEnum
*/
public PeninsulaEnum getPeninsulaEnum() {
return peninsulaEnum;
}
/**
* @param peninsulaEnum
* the peninsulaEnum to set
*/
public void setPeninsulaEnum(PeninsulaEnum peninsulaEnum) {
this.peninsulaEnum = peninsulaEnum;
}
}
与采用Observer的方式不同,如果使用EventListener来进行观察。那么,就必须自己来实现观察者的管理和触发。因此,这里给出如下的观察者的实现:
/**
* 被观察者实例。
*
* @author ibm
*
*/
public class NorthKoreaSubject {
/** 保存观察者实例的容器。 */
private final Vector repo = new Vector();
/**
* 添加事件监听器。
*
* @param eventListener
*/
public synchronized void addEventListener(EventListener eventListener) {
repo.addElement(eventListener);
}
public void notifyListener(EventObject e) throws IllegalAccessException {
Object[] localArr;
if (repo == null) {
throw new IllegalAccessException("Vector is empty");
}
synchronized (this) {
if (!repo.isEmpty()) {
localArr = repo.toArray();
for (Object element : localArr) {
((GovernmentListener) element).handler(e);
}
}
}
}
}
至此,被观察者的实现完成了。下面对观察者的实现进行介绍。首先,EventListener是一个没有任何方法的标识接口,为了能够表示观察者需要统一完成的动作,我们需要自定出一个接口,该接口继承自EventListener接口。
/**
* 监听器实例。
*
* @author ibm
*
*/
public interface GovernmentListener extends EventListener {
/** 接口中包含了事件对象。 */
void handler(EventObject e);
}
同样,中国和美国分别是这两个接口的实现。
/**
* 监听器的实现,中国。
* @author ibm
*
*/
public class ChinaEventListener implements GovernmentListener {
@Override
public void handler(EventObject e) {
// TODO Auto-generated method stub
if (e instanceof PeninsulaSituation) {
PeninsulaEnum situation = ((PeninsulaSituation) e)
.getPeninsulaEnum();
if (situation == PeninsulaEnum.KIMJIONIIDEAD) {
System.out.println(" --中国外交部发来唁电");
}
if (situation == PeninsulaEnum.UNCLEAN) {
System.out.println(" --中国外交部表示谴责");
}
}
}
}
/**
* 监听器的实现,美国。
*
* @author ibm
*
*/
public class AmericanEventListener implements GovernmentListener {
@Override
public void handler(EventObject e) {
// TODO Auto-generated method stub
if (e instanceof PeninsulaSituation) {
PeninsulaEnum situation = ((PeninsulaSituation) e)
.getPeninsulaEnum();
if (situation == PeninsulaEnum.KIMJIONIIDEAD) {
System.out.println(" --白宫表示毫无压力");
}
if (situation == PeninsulaEnum.UNCLEAN) {
System.out.println(" --白宫很生气,后果很严重");
}
}
}
}
下面是测试类
/**
* 事件监听器启动实例。
*
* @author ibm
*
*/
public class EventListenerStartDemo {
private final static NorthKoreaSubject subject = new NorthKoreaSubject();
public static void main(String[] args) {
try {
EventListener china = new ChinaEventListener();
EventListener american = new AmericanEventListener();
subject.addEventListener(china);
subject.addEventListener(american);
EventObject event1 = new PeninsulaSituation(
PeninsulaEnum.KIMJIONIIDEAD);
EventObject event2 = new PeninsulaSituation(PeninsulaEnum.UNCLEAN);
System.out.println("Kim Jong II -- 我挂了");
subject.notifyListener(event1);
System.out.println("Kim Jong II -- 我们有原子弹了思密达");
subject.notifyListener(event2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
其执行的结果是:
Kim-Jong-II:我们有核原子弹了思密达!
--白宫很生气,后果很严重
--中国外交部表示谴责!
Kim-Jong-II:我挂了~~~
--白宫表示毫无压力
--中国外交部发来唁电
以上是放假,闲来无事自娱自乐的一些整理,希望大家拍砖!