this.name = name;
}
public String getName() {
return name;
}
//读者可以关注某一位作者,关注则代表把自己加到作者的监听器列表里
public void subscribe(String writerName){
WriterManager.getInstance().getWriter(writerName).registerListener(this);
}
//读者可以取消关注某一位作者,取消关注则代表把自己从作者的监听器列表里注销
public void unsubscribe(String writerName){
WriterManager.getInstance().getWriter(writerName).unregisterListener(this);
}
public void addNovel(WriterEvent writerEvent) {
Writer writer = writerEvent.getWriter();
System.out.println(name+"知道" + writer.getName() + "发布了新书《" + writer.getLastNovel() + "》,非要去看!");
}
}
public class Reader implements WriterListener{
private String name;
public Reader(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
//读者可以关注某一位作者,关注则代表把自己加到作者的监听器列表里
public void subscribe(String writerName){
WriterManager.getInstance().getWriter(writerName).registerListener(this);
}
//读者可以取消关注某一位作者,取消关注则代表把自己从作者的监听器列表里注销
public void unsubscribe(String writerName){
WriterManager.getInstance().getWriter(writerName).unregisterListener(this);
}
public void addNovel(WriterEvent writerEvent) {
Writer writer = writerEvent.getWriter();
System.out.println(name+"知道" + writer.getName() + "发布了新书《" + writer.getLastNovel() + "》,非要去看!");
}
} 读者类的变化,首先本来是实现Observer接口,现在要实现WriterListener接口,响应的update方法就改为我们定义的addNovel方法,当中的响应基本没变。另外就是关注和取消关注的方法中,原来是给作者类添加观察者和删除观察者,现在是注册监听器和注销监听器,几乎是没什么变化的。
我们彻底将刚才的观察者模式改成了事件驱动,现在我们使用事件驱动的类再运行一下客户端,其中客户端代码和WriterManager类的代码是完全不需要改动的,直接运行客户端即可。我们会发现得到的结果与观察者模式一模一样。
走到这里我们发现二者可以达到的效果一模一样,那么两者是不是一样呢?
答案当然是否定的,首先我们从实现方式上就能看出,事件驱动可以解决观察者模式的问题,但反过来则不一定,另外二者所表达的业务场景也不一样,比如上述例子,使用观察者模式更贴近业务场景的描述,而使用事件驱动,从业务上讲,则有点勉强。
二者除了业务场景的区别以外,在功能上主要有以下区别。
1,,观察者模式中观察者的响应理论上讲针对特定的被观察者是唯一的(说理论上唯一的原因是,如果你愿意,你完全可以在update方法里添加一系列的elseif去产生不同的响应,但LZ早就说过,你应该忘掉elseif),而事件驱动则不是,因为我们可以定义自己感兴趣的事情,比如刚才,我们可以监听作者发布新书,我们还可以在监听器接口中定义其它的行为。再比如tomcat中,我们可以监听servletcontext的init动作,也可以监听它的destroy动作。
2,虽然事件驱动模型更加灵活,但也是付出了系统的复杂性作为代价的,因为我们要为每一个事件源定制一个监听器以及事件,这会增加系统的负担,各位看看tomcat中有多少个监听器和事件类就知道了。
3,另外观察者模式要求被观察者继承Observable类,这就意味着如果被观察者原来有父类的话,就需要自己实现被观察者的功能,当然,这一尴尬事情,我们可以使用适配器模式弥补,但也不可避免的造成了观察者模式的局限性。事件驱动中事件源则不需要,因为事件源所维护的监听器列表是给自己定制的,所以无法去制作一个通用的父类去完成这个工作。
4,被观察者传送给观察者的信息是模糊的,比如update中第二个参数,类型是Object,这需要观察者和被观察者之间有约定才可以使用这个参数。而在事件驱动模型中,这些信息是被封装在Event当中的,可以更清楚的告诉监听器,每个信息都是代表的什么。
由于上述使用事件驱动有点勉强,所以LZ给各位模拟一个我们js当中的一个事件驱动模型,就是按钮的点击事件。
在这个模型当中,按钮自然就是事件源,而事件的种类有很多,比如点击(click),双击(dblclick),鼠标移动事件(mousemove)。我们的监听器与事件个数是一样的,所以这也是事件驱动的弊端,我们需要一堆事件和监听器,下面LZ一次性给出这三种事件和监听器,其余还有很多事件,类似,LZ这里省略。
[java]
import java.util.EventObject;
//按钮事件基类
public abstract class ButtonEvent extends EventObject{
public ButtonEvent(Object source) {
super(source);
}
public Button getButton(){
return (Button) super.getSource();
}
}
//点击事件
class ClickEvent exte