Java设计模式:观察者模式以及Servlet中的Listener
来源:互联网 发布:java相关的书籍 编辑:程序博客网 时间:2024/06/13 00:01
观察者模式(Observer Pattern)也称发布订阅模式,它是一种在实际开发中经常用到的一种模式。
观察者模式定义:定义对象一种一对多的依赖关系,使得每当一个对象改变状态时,则所依赖它的对象会得到通知并被自动更新。
观察者类图如下:
图1 观察者模式的类图
观察者模式的角色如下:
- 关联行为场景
- 事件多级触发场景
- 跨系统的消息交换场景,如消息队列的处理机制
Clickable.java/** * 被观察者接口 * @author HuiSir */public interface Clickable {//单击void click();//添加单击事件的观察者void addClickableObserver(ClickableObserver observer);//删除单击事件的观察者 void removeClickableObserver(ClickableObserver observer);}
ClickableObserver.java/** * 观察者接口 * @author HuiSir */public interface ClickableObserver {//发生单击事件时的操作void clicked(Clickable clickable);}
按钮控件,因按钮是可单击的控件,所以Button类实现Clickable接口。代码如下。
Button.javaimport java.util.ArrayList;/** *Clickable 接口的实现类 * 观察者接口 * @author HuiSir */public class Button implements Clickable {//存储注册过的单击事件观察者ArrayList<ClickableObserver>observers = new ArrayList<ClickableObserver>();//按钮信息String color; int x , y ;@Overridepublic void click() {System.out.println("按钮被单击");//执行所有观察者的事件的处理方法for(int i = observers.size() - 1 ; i >= 0 ; i--){ observers.get(i).clicked(this);}}@Overridepublic void addClickableObserver(ClickableObserver observer) { observers.add(observer);}@Overridepublic void removeClickableObserver(ClickableObserver observer) {observers.remove(observer);}@Overridepublic String toString(){return "按钮颜色: " + color + ",坐标" + x + "," + y ;}}
ChangeColorObserver.java/** * 观察按钮的颜色修改的观察者 * @author HuiSir */public class ChangeColorObserver implements ClickableObserver {@Overridepublic void clicked(Clickable clickable) {Button b = (Button)clickable;b.color = "红色" ;}}
ChangeCoordinateObserver.java/** * 观察坐标业务操作的观察者 * @author HuiSir */public class ChangeCoordinateObserver implements ClickableObserver {@Overridepublic void clicked(Clickable clickable) {// TODO Auto-generated method stubButton b = (Button)clickable;b.x = 100 ;b.y = 90 ;}}OtherObserver。javapublic class OtherObserver implements ClickableObserver {@Overridepublic void clicked(Clickable clickable) {// TODO Auto-generated method stubSystem.out.println("其他操作被执行");}}Test.javapublic class Test {/** * @author HuiSir * 测试类 */public static void main(String[] args) {Button button = new Button () ;button.color = "白色";button.x = 0 ;button.y = 0 ;button.addClickableObserver(new ChangeColorObserver());button.addClickableObserver(new ChangeCoordinateObserver());button.addClickableObserver(new OtherObserver());//button 的click 事件 单击后将触发在button中注册的观察者,然后观察者调用他的方法,从而//执行其对应的方法。很简单。button.click();System.out.println(button);}}Test.javapublic class Test {/** * @author HuiSir * 测试类 */public static void main(String[] args) {Button button = new Button () ;button.color = "白色";button.x = 0 ;button.y = 0 ;button.addClickableObserver(new ChangeColorObserver());button.addClickableObserver(new ChangeCoordinateObserver());button.addClickableObserver(new OtherObserver());//button 的click 事件 单击后将触发在button中注册的观察者,然后观察者调用他的方法,从而//执行其对应的方法。很简单。button.click();System.out.println(button);}}运行结果如下:
按钮被单击
其他操作被执行
按钮颜色: 红色,坐标100,90
从运行结果可以看出,按钮原来的“白色”、坐标“0,0”、单击按钮后,按钮的属性变为“红色”、坐标“100,90” ,充分演示了观察者模式在多级触发场景中的应用,体现了类之间的一种一对多的依赖关系。
Servlet中的Listener
再说Servlet中的Listener之前, 先说说观察者模式的另一种形态——事件驱动模型。与上面提到的观察者模式的主题角色一样, 事件驱动模型包括事件源, 具体事件, 监听器, 具体监听器。
Servlet中的Listener就是典型的事件驱动模型。
JDK中有一套事件驱动的类, 包括一个统一的监听器接口和一个统一的事件源, 源码如下:
/** * A tagging interface that all event listener interfaces must extend. * @since JDK1.1 */public interface EventListener {}
ChangeColorObserver.java这是一个标志接口, JDK规定所有监听器必须继承这个接口。public class EventObject implements java.io.Serializable { private static final long serialVersionUID = 5516075349620653480L; /** * The object on which the Event initially occurred. */ protected transient Object source; /** * Constructs a prototypical Event. * * @param source The object on which the Event initially occurred. * @exception IllegalArgumentException if source is null. */ public EventObject(Object source) { if (source == null) throw new IllegalArgumentException("null source"); this.source = source; } /** * The object on which the Event initially occurred. * * @return The object on which the Event initially occurred. */ public Object getSource() { return source; } /** * Returns a String representation of this EventObject. * * @return A a String representation of this EventObject. */ public String toString() { return getClass().getName() + "[source=" + source + "]"; }}EvenObject是JDK给我们规定的一个统一的事件源。EvenObject类中定义了一个事件源以及获取事件源的get方法。
下面就分析一下Servlet Listener的运行流程。
Servlet Listener的组成
目前, Servlet中存在6种两类事件的监听器接口, 具体如下图:
具体触发情境如下表:
一个具体的Listener触发过程
我们以ServletRequestAttributeListener为例, 来分析一下此处事件驱动的流程。
首先一个Servlet中, HttpServletRequest调用setAttrilbute方法时, 实际上是调用的org.apache.catalina.connector.request#setAttrilbute方法。 我们看下它的源码:
public void setAttribute(String name, Object value) { ... //上面的逻辑代码已省略 // 此处即通知监听者 notifyAttributeAssigned(name, value, oldValue); }下面是notifyAttributeAssigned(String name, Object value, Object oldValue)的源码
private void notifyAttributeAssigned(String name, Object value, Object oldValue) { //从容器中获取webAPP中定义的Listener的实例对象 Object listeners[] = context.getApplicationEventListeners(); if ((listeners == null) || (listeners.length == 0)) { return; } boolean replaced = (oldValue != null); //创建相关事件对象 ServletRequestAttributeEvent event = null; if (replaced) { event = new ServletRequestAttributeEvent( context.getServletContext(), getRequest(), name, oldValue); } else { event = new ServletRequestAttributeEvent( context.getServletContext(), getRequest(), name, value); } //遍历所有监听器列表, 找到对应事件的监听器 for (int i = 0; i < listeners.length; i++) { if (!(listeners[i] instanceof ServletRequestAttributeListener)) { continue; } //调用监听器的方法, 实现监听操作 ServletRequestAttributeListener listener = (ServletRequestAttributeListener) listeners[i]; try { if (replaced) { listener.attributeReplaced(event); } else { listener.attributeAdded(event); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); context.getLogger().error(sm.getString("coyoteRequest.attributeEvent"), t); // Error valve will pick this exception up and display it to user attributes.put(RequestDispatcher.ERROR_EXCEPTION, t); } } }上面的例子很清楚的看出ServletRequestAttributeListener是如何调用的。用户只需要实现监听器接口就行。Servlet中的Listener几乎涵盖了Servlet整个生命周期中你感兴趣的事件, 灵活运用这些Listenser可以使程序更加灵活。
总结
观察者模式定义了对象之间一对多的关系, 当一个对象(被观察者)的状态改变时, 依赖它的对象都会收到通知。可以应用到发布——订阅, 变化——更新这种业务场景中。
观察者和被观察者之间用松耦合的方式, 被观察者不知道观察者的细节, 只知道观察者实现了接口。
事件驱动模型更加灵活,但也是付出了系统的复杂性作为代价的,因为我们要为每一个事件源定制一个监听器以及事件,这会增加系统的负担。
观察者模式的核心是先分清角色、定位好观察者和被观察者、他们是多对一的关系。实现的关键是要建立观察者和被观察者之间的联系、比如在被观察者类中有个集合是用于存放观察者的、当被检测的东西发生改变的时候就要通知所有观察者。在观察者的构造方法中将被观察者传入、同时将本身注册到被观察者拥有的观察者名单中、即observers这个list中。
1.观察者模式优点:
(1)抽象主题只依赖于抽象观察者
(2)观察者模式支持广播通信
(3)观察者模式使信息产生层和响应层分离
2.观察者模式缺点:
(1)如一个主题被大量观察者注册,则通知所有观察者会花费较高代价
(2)如果某些观察者的响应方法被阻塞,整个通知过程即被阻塞,其它观察者不能及时被通知
0 0
- Java设计模式:观察者模式以及Servlet中的Listener
- java中的观察者设计模式
- 浅析Java设计模式中的观察者模式
- java设计模式-----观察者
- JAVA 观察者设计模式
- java观察者设计模式
- java观察者设计模式
- java 观察者设计模式
- JAVA-观察者设计模式
- JAVA设计模式--观察者
- Java---观察者设计模式
- Java设计模式:观察者
- Java设计模式-观察者
- java观察者设计模式
- java listener 与 观察者模式入门
- 观察者(Listener)模式
- java设计模式-观察者模式
- java设计模式---观察者模式
- Apache Commons 工具类介绍及简单使用
- event.clientX event.clientY 鼠标移动位置
- 关于无法导入unity资源包的问题
- 多态
- 杭电--2069--Coin_Change(简单枚举题)
- Java设计模式:观察者模式以及Servlet中的Listener
- MyBatis_1
- 【进阶】MySQL中的子查询和联合查询
- SVM人脸识别
- 解决Windows安装解压版MySQL出现服务正在启动-服务无法启动的问题
- 在SSH框架中注入HibernateTemplate进行分页等相关查询
- 单例模式.md
- State与Transition之Transition
- 面试中被问到的概率题