java设计模式--观察者模式和事件监听器模式

文章转载于:http://www.java2000.net/p9452

复习设计模式,看到observer观察者模式,说法是该模式和iterator迭代器模式类似已经被整合进jdk,但是jdk提供了两种接口: 

一、java.util.Observer
—— 观察者接口 对应:
 
java.util.Observable
——受查者根类 

二、java.util.EventListener —— 事件监听/处理接口
对应:
 
java.util.EventObject ——
事件(状态)对象根类 

研究了一下发现这两种接口的目的、功能其实是一样的(仅在事件模型的结构上有些许差异),先看EventListener事件监听器模式: 

1、首要定义事件源对象(事件源相当于单击按钮事件当中的按钮对象、属于被监听者):

查看复制到剪切板打印

  1. public class DemoSource {

  2. private Vector repository = new Vector();//监听自己的监听器队列

  3. public DemoSource(){}

  4. public void addDemoListener(DemoListener dl) {

  5. repository.addElement(dl);

  6. }

  7. public void notifyDemoEvent() {//通知所有的监听器

  8. Enumeration enum = repository.elements();

  9. while(enum.hasMoreElements()) {

  10. DemoListener dl = (DemoListener)enum.nextElement();

  11. dl.handleEvent(new DemoEvent(this));

  12. }

  13. }

  14. }

[Java] view plaincopy

  1. public class DemoSource {

  2. private Vector repository = new Vector();//监听自己的监听器队列

  3. public DemoSource(){}

  4. public void addDemoListener(DemoListener dl) {

  5. repository.addElement(dl);

  6. }

  7. public void notifyDemoEvent() {//通知所有的监听器

  8. Enumeration enum = repository.elements();

  9. while(enum.hasMoreElements()) {

  10. DemoListener dl = (DemoListener)enum.nextElement();

  11. dl.handleEvent(new DemoEvent(this));

  12. }

  13. }

  14. }

2、其次定义事件(状态)对象(该事件对象包装了事件源对象、作为参数传递给监听器、很薄的一层包装类):

查看复制到剪切板打印

  1. public class DemoEvent extends java.util.EventObject {

  2. public DemoEvent(Object source) {

  3. super(source);//source—事件源对象—如在界面上发生的点击按钮事件中的按钮

  4. //所有 Event 在构造时都引用了对象 "source",在逻辑上认为该对象是最初发生有关 Event 的对象

  5. }

  6. public void say() {

  7. System.out.println("This is say method...");

  8. }

  9. }

[Java] view plaincopy

  1. public class DemoEvent extends java.util.EventObject {

  2. public DemoEvent(Object source) {

  3. super(source);//source—事件源对象—如在界面上发生的点击按钮事件中的按钮

  4. //所有 Event 在构造时都引用了对象 "source",在逻辑上认为该对象是最初发生有关 Event 的对象

  5. }

  6. public void say() {

  7. System.out.println("This is say method...");

  8. }

  9. }

3、最后定义我们的事件侦听器接口如下:

查看复制到剪切板打印

  1. public interface DemoListener extends java.util.EventListener {

  2. //EventListener是所有事件侦听器接口必须扩展的标记接口、因为它是无内容的标记接口、

  3. //所以事件处理方法由我们自己声明如下:

  4. public void handleEvent(DemoEvent dm);

  5. }

[Java] view plaincopy

  1. public interface DemoListener extends java.util.EventListener {

  2. //EventListener是所有事件侦听器接口必须扩展的标记接口、因为它是无内容的标记接口、

  3. //所以事件处理方法由我们自己声明如下:

  4. public void handleEvent(DemoEvent dm);

  5. }

4、测试代码

查看复制到剪切板打印

  1. //定义具体的事件监听器:

  2. public class DemoListener1 implements DemoListener {

  3. public void handleEvent(DemoEvent de) {

  4. System.out.println("Inside listener1...");

  5. de.say();//回调

  6. }

  7. }
  8. public class TestDemo {

  9. DemoSource ds;
  10. public TestDemo(){

  11. try{

  12. ds = new DemoSource();
  13. //将监听器在事件源对象中登记:

  14. DemoListener1 l1 = new DemoListener1();

  15. ds.addDemoListener(l1);

  16. ds.addDemoListener(new DemoListener() {

  17. public void handleEvent(DemoEvent event) {

  18. System.out.println("Method come from 匿名类...");

  19. }

  20. });
  21. ds.notifyDemoEvent();//触发事件、通知监听器
  22. }catch(Exception ex) {ex.printStackTrace();}

  23. }
  24. public static void main(String args[]) {

  25. new TestDemo();

  26. }

  27. }

[Java] view plaincopy

  1. //定义具体的事件监听器:

  2. public class DemoListener1 implements DemoListener {

  3. public void handleEvent(DemoEvent de) {

  4. System.out.println("Inside listener1...");

  5. de.say();//回调

  6. }

  7. }
  8. public class TestDemo {

  9. DemoSource ds;
  10. public TestDemo(){

  11. try{

  12. ds = new DemoSource();
  13. //将监听器在事件源对象中登记:

  14. DemoListener1 l1 = new DemoListener1();

  15. ds.addDemoListener(l1);

  16. ds.addDemoListener(new DemoListener() {

  17. public void handleEvent(DemoEvent event) {

  18. System.out.println("Method come from 匿名类...");

  19. }

  20. });
  21. ds.notifyDemoEvent();//触发事件、通知监听器
  22. }catch(Exception ex) {ex.printStackTrace();}

  23. }
  24. public static void main(String args[]) {

  25. new TestDemo();

  26. }

  27. }

再看Observer观察者模式: 
Observer和EventListener的区别仅仅在于它提前声明了事件处理方法: 
update(Observable
o, Object
arg) 
Observer模式当中不存在对应EventObject的角色,Observable被观察者就兼具了source事件源和EventObject事件对象两种角色,模型更简洁。 
Observable被观察者根类就持有了观察者队列,也定义了类似notifyDemoEvent()的notifyObservers()方法... 

除了结构有差异外实在看不出Observer观察者模式和EventListener事件监听/处理模式的不一样!请教二者还有什么差异吗? 

回复: 

也不能这么说 
我看了一下Observer、Observable的jdk源码,Observer接口没什么可说的仅仅是声明了一个update方法而已,相当于我在interface
DemoListener extends
java.util.EventListener接口中定义的:handleEvent方法。 
为什么声明呢?最主要的是Observer模式比较EventListener的不同之处还在于将大部分工作收归Observable根类完成。 
我又看了看Observable根类,虽然代码也很短小但是比较精悍,至少要我自己写考虑不了这么全面。好比java2集合,我们自己也能做些hashmap、arraylist、栈、队但是可靠性应该是比不上jdk提供的。 

总结一下Observer模式和EventListener的主要不同之处: 

一、模型结构不同:EventListener是传统的c/s界面事件模型,分事件源和事件(状态)角色,事件源要经过事件的包装、成为事件的属性之一再传递给事件监听/处理者,这个事件监听者就相当于观察者。我记得好像VB或C#也是这种模型...而Observer模式的模型就简洁多了,没有分事件源和事件,二者合二为一为一个角色:被观察者,从字面语义上也应该这样,另一个是观察者角色。 

二、就是我上面说的Observer模式比较EventListener的不同之处还在于将大部分工作收归Observable根类实现了、包括定义监听者队列、通知方法都实现了,我们只要继承、调用和传值就行了。 

现在想想可能是EventListener监听机制是从c/s时代就延续下来的,而Observer模式则是和iterator迭代器模式同样被整合进jdk的,所以现在这两种功用存在交叉的api会同时存在。 

也贴出来Observer模式演示代码来对比

查看复制到剪切板打印

  1. //观察者

  2. class Watcher implements java.util.Observer {

  3. public void update(java.util.Observable obj, Object arg) {

  4. System.out.println("Update() called, count is "

  5. + ((Integer) arg).intValue());

  6. }

  7. }
  8. //被观察者

  9. class BeingWatched extends java.util.Observable {

  10. void counter(int period) {

  11. for(; period>=0; period-- ) {

  12. setChanged();

  13. notifyObservers(new Integer(period));

  14. try {

  15. Thread.sleep(100);

  16. } catch( InterruptedException e) {

  17. System.out.println("Sleep interrupeted" );

  18. }

  19. }

  20. }

  21. };
  22. //演示

  23. public class ObserverDemo {

  24. public static void main(String[] args) {

  25. BeingWatched beingWatched = new BeingWatched();//受查者

  26. Watcher watcher = new Watcher();//观察者

  27. beingWatched.addObserver(watcher);

  28. beingWatched.counter(10);

  29. }

  30. }

[Java] view plaincopy

  1. //观察者

  2. class Watcher implements java.util.Observer {

  3. public void update(java.util.Observable obj, Object arg) {

  4. System.out.println("Update() called, count is "

  5. + ((Integer) arg).intValue());

  6. }

  7. }
  8. //被观察者

  9. class BeingWatched extends java.util.Observable {

  10. void counter(int period) {

  11. for(; period>=0; period-- ) {

  12. setChanged();

  13. notifyObservers(new Integer(period));

  14. try {

  15. Thread.sleep(100);

  16. } catch( InterruptedException e) {

  17. System.out.println("Sleep interrupeted" );

  18. }

  19. }

  20. }

  21. };
  22. //演示

  23. public class ObserverDemo {

  24. public static void main(String[] args) {

  25. BeingWatched beingWatched = new BeingWatched();//受查者

  26. Watcher watcher = new Watcher();//观察者

  27. beingWatched.addObserver(watcher);

  28. beingWatched.counter(10);

  29. }

  30. }

回复: 
查阅了一些相关的东东 
原来这两种api可以说都是基于:订阅-发布模式的事件/消息通知模式,二者应该都算是“推”方式吧,就是被监控者将消息通知给所有监控者。 
1、订阅:Observable.addObserver; 
事件源.addDemoListener(这个方法是自己定义的)。 

2、发布:Observable需要两步:setChanged()、notifyObservers(newValue); 
事件源.notifyDemoEvent()(这个方法也是自己定义的)。 

有人说Observer是设计模式中的皇后,很多系统级实现都是这种方式,我觉得是不是搞混了,因为我看java.util.Observer的api没什么下级接口或实现类。 
反倒是相似的java.util.EventListener有大量下级接口和实现类,著名的包括: 
java.beans.PropertyChangeListener 
javax.servlet.http.HttpSessionListener... 
以及java界面api里的很多... 
这么看EventListener比Observer应用多得多,我猜想是否是因为EventListener的限制较少、没有规定事件处理方法名、比如HttpSessionListener就根据自己的应用领域定义事件处理方法: 
sessionCreated(HttpSessionEvent
se) 和 
sessionDestroyed(HttpSessionEvent
se) 

如果用Observer就只能叫update了。

java设计模式--观察者模式和事件监听器模式,布布扣,bubuko.com

时间: 2024-12-17 06:54:32

java设计模式--观察者模式和事件监听器模式的相关文章

Java设计模式补充:回调模式、事件监听器模式、观察者模式(转)

一.回调函数 为什么首先会讲回调函数呢?因为这个是理解监听器.观察者模式的关键. 什么是回调函数 所谓的回调,用于回调的函数. 回调函数只是一个功能片段,由用户按照回调函数调用约定来实现的一个函数. 有这么一句通俗的定义:就是程序员A写了一段程序(程序a),其中预留有回调函数接口,并封装好了该程序.程序员B要让a调用自己的程序b中的一个方法,于是,他通过a中的接口回调自己b中的方法. 举个例子: 这里有两个实体:回调抽象接口.回调者(即程序a) 回调接口(ICallBack ) public i

Java设计模式(十一)访问者模式 中介者模式

(二十一)访问者模式 对已存在的类进行扩展,通常需要增加方法,但是如果需要的行为与现有的对象模型不一致,或者无法修改现有代码.在这种情况下,不更改类的层次结构,就无法扩展该层次结构的行为.如果运用了访问者模式,就可以支持开发人员扩展该类层次结构的行为. 和解释器模式一样,访问者模式通常是基于合成模式的. 访问者模式在不改变类层次结构的前提下,对该层次结构进行扩展. interface Visitor{ public void visit(VisiSubject sub); } interface

Java设计模式(十) 备忘录模式 状态模式

(十九)备忘录模式 备忘录模式目的是保存一个对象的某个状态,在适当的时候恢复这个对象. class Memento{ private String value; public Memento(String value){ this.value = value; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } } class Storage

Java设计模式(五)外观模式 桥梁模式

(九)外观模式 外观模式为子系统提供一个接口,便于使用.解决了类与类之间关系的,外观模式将类之间的关系放在一个 Facade 类中,降低了类类之间的耦合度,该模式不涉及接口. class CPU { public void startup(){ System.out.println("cpu start"); } public void shutdown(){ System.out.println("cpu stop"); } } class Memory { pu

Java设计模式(六)合成模式 享元模式

(十一)合成模式 Composite 合成模式是一组对象的组合,这些对象可以是容器对象,也可以是单对象.组对象允许包含单对象,也可以包含其他组对象,要为组合对象和单对象定义共同的行为.合成模式的意义是 保证客户端调用单对象与组合对象的一致性. class TreeNode{ private String name; private TreeNode parent; private Vector<TreeNode> children = new Vector<TreeNode>();

Java设计模式(七)策略模式 模板模式

(十三)策略模式 策略模式定义了多个封装起来的算法,封装的算法可以相互替换,并且算法的变化不会影响到使用算法的客户.借用另一位大神的例子. interface ICalculator{ public int calculate(String exp); } abstract class AbstractCalculator{ public int[] split(String exp,String opt){ String array[] = exp.split(opt); int arrayI

Java设计模式(三)原型模式

(五)原型模式 Prototype 原型模式目的是复制一个现有对象来生成新的对象,而不是通过实例化的方式.原型模式需要实现 Cloneable 接口,覆写clone方法,复制分为浅复制.深复制. 浅复制:将一个对象复制后,基本数据类型的变量都重新创建,引用类型,指向的还是原对象所指向的. 深复制:讲一个对象复制后,不论基本数据类型和引用类型,都是重新创建,是完全的彻底的复制. public class ProtoType { public static void main(String[] ar

Java设计模式----观察者模式详解

[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3899208.html 联系方式:[email protected] [正文] 一.观察者模式的定义: 简单地说,观察者模式定义了一个一对多的依赖关系,让一个或多个观察者对象监听一个主题对象.这样一来,当被观察者状态发生改变时,需要通知相应的观察者,使这些观察者对象能够自动更新.例如:GUI中的事件

初探Java设计模式3:行为型模式(策略,观察者等)

行为型模式 行为型模式关注的是各个类之间的相互作用,将职责划分清楚,使得我们的代码更加地清晰. 策略模式 策略模式太常用了,所以把它放到最前面进行介绍.它比较简单,我就不废话,直接用代码说事吧. 下面设计的场景是,我们需要画一个图形,可选的策略就是用红色笔来画,还是绿色笔来画,或者蓝色笔来画. 首先,先定义一个策略接口: public interface Strategy { public void draw(int radius, int x, int y); } 然后我们定义具体的几个策略: