From : http://canann.iteye.com/blog/1814653
12.3.3 Java中的观察者模式
估计有些朋友在看前面的内容的时候,心里就嘀咕上了,Java里面不是已经有了观察者模式的部分实现吗,为何还要全部自己从头做呢?
主要是为了让大家更好的理解观察者模式本身,而不用受Java语言实现的限制。
好了,下面就来看看如何利用Java中已有的功能来实现观察者模式。在java.util包里面有一个类Observable,它实现了大部分我们需要的目标的功能;还有一个接口Observer,它里面定义了update的方法,就是观察者的接口。
因此,利用Java中已有的功能来实现观察者模式非常简单,跟前面完全由自己来实现观察者模式相比有如下改变:
- 不需要再定义观察者和目标的接口了,JDK帮忙定义了
- 具体的目标实现里面不需要再维护观察者的注册信息了,这个在Java中的Observable类里面,已经帮忙实现好了
- 触发通知的方式有一点变化,要先调用setChanged方法,这个是Java为了帮助实现更精确的触发控制而提供的功能
- 具体观察者的实现里面,update方法其实能同时支持推模型和拉模型,这个是Java在定义的时候,就已经考虑进去了
好了,说了这么多,还是看看例子会比较直观。
(1)新的目标的实现,不再需要自己来实现Subject定义,在具体实现的时候,也不是继承Subject了,而是改成继承Java中定义的Observable,示例代码如下:
/** * 报纸对象,具体的目标实现 */ public class NewsPaper extends java.util.Observable { /** * 报纸的具体内容 */ private String content; /** * 获取报纸的具体内容 * @return 报纸的具体内容 */ public String getContent() { return content; } /** * 示意,设置报纸的具体内容,相当于要出版报纸了 * @param content 报纸的具体内容 */ public void setContent(String content) { this.content = content; //内容有了,说明又出新报纸了,那就通知所有的读者 //注意在用Java中的Observer模式的时候,下面这句话不可少 this.setChanged(); //然后主动通知,这里用的是推的方式 this.notifyObservers(this.content); //如果用拉的方式,这么调用 //this.notifyObservers(); } } |
(2)再看看新的观察者的实现,不是实现自己定义的观察者接口,而是实现由Java提供的Observer接口,示例代码如下:
/** * 真正的读者,为了简单就描述一下姓名 */ public class Reader implements java.util.Observer { /** * 读者的姓名 */ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void update(Observable o, Object obj) { //这是采用推的方式 System.out.println(name +"收到报纸了,阅读先。目标推过来的内容是==="+obj);
//这是获取拉的数据 System.out.println(name +"收到报纸了,阅读先。主动到目标对象去拉的内容是===" +((NewsPaper)o).getContent());
} } |
(3)客户端使用
客户端跟前面的写法没有太大改变,主要在注册阅读者的时候,调用的方法跟以前不一样了,示例代码如下:
public class Client { public static void main(String[] args) { //创建一个报纸,作为被观察者 NewsPaper subject = new NewsPaper(); //创建阅读者,也就是观察者 Reader reader1 = new Reader(); reader1.setName("张三");
Reader reader2 = new Reader(); reader2.setName("李四");
Reader reader3 = new Reader(); reader3.setName("王五");
//注册阅读者 subject.addObserver(reader1); subject.addObserver(reader2); subject.addObserver(reader3);
//要出报纸啦 subject.setContent("本期内容是观察者模式"); } } |