网站首页
JSP空间
动态资讯
开源项目
技术文档
资源下载
J2EE资源
客户论坛
在线支付
 
  技术文档>>JAVA>>新手入门>>基础入门>查看文档  
  关于装饰servlet request对象简介图     
  文章作者:未知  文章来源:水木森林  
  查看:50次  录入:管理员--2007-11-17  
 
  摘要
  
  装饰模式是erich gamma等人所著的《设计模式:可利用面向对象软件的基础》一书中众多模式之一。一般来说,此模式在设计swing的程序员中比较流行,他们用它来改进软件。今天,即使有许多程序是基于web应用的,装饰模式仍有用武之地,在j2ee的环境下也有使用的价值。
  
  本文说明了如何将装饰模式应用到servlet request对象上。首先,提出了一个与servlet filter有关的问题,并解释了随之而引入的装饰模式。然后,讨论了如何在servlet环境下使用此模式,并列出了使用此模式的几个比较有名的基于servlet的项目。最后,文章通过实现一个删除空白符的filter例子,演示了装饰模式在servlet中的使用。
  
  简介
  
  servlet规范中所引入的filter令人心动不已,因为它引入了一个功能强大的拦截模式。filter是这样一种java对象,它能在request到达servlet的服务方法之前拦截httpservletrequest对象,而在服务方法转移控制后又能拦截httpservletresponse对象。你可以使用filter来实现特定的任务,比如验证用户输入,以及压缩web内容。但你拟富有成效地使用过滤器的念头却被你不能改变httpservletrequest对象的参数的现实扫了兴,因为java.util.map所包装的httpservletrequest对象的参数是不可改变的。这极大地缩减了filter的应用范围。至少在一半的时间里,你希望可以改变准备传送给filter的对象。如果在httpservletrequest对象到达struts的action servlet之前,我们可以通过一个filter将用户输入的多余空格去掉,难道不是更美妙吗?这样的话,你就不必等到在struts的action表单验证方法中才进行这项工作了。
  
  幸运的是,尽管你不能改变不变对象本身,但你却可以通过使用装饰模式来改变其状态。
  
  装饰模式
  
  在继承中,你可以通过继承一个父类并覆盖你希望改变的方法来改变对象状态。然而,如果这个对象是由程序的另一个子模块,例如对象工厂 (这里所说的工厂是工厂模式中的术语,下同。译者注) 或是servlet容器所产生的,继承就无能为力了。
  
  装饰模式可用来增加一个现有对象的功能,或是改变其状态。与其使用继承方式来扩展此类,这个模式将一个对象包装成另外一个对象。图1是装饰模式的uml类图。
  
 关于装饰servlet request对象简介图(图一)

  
图1:装饰模式

  
  在图1中,component是一个接口,其具体实现是concretecomponent。要改变component的状态,你可以修改concretecomponent或是扩展它 (通过继承或实现接口的方式,译者注)。然而,如果concretecomponent来自于一个工厂,你却无计可施。你所能做的,就是创建一个同为实现了component接口的装饰类。在图1中,这个装饰类的角色就由decorator来扮演,在程序中通常表现为接口或抽象类。decorator类的一个特性就是,它有一个接收component对象的构造方法。你将拟装饰的对象传递给这个构造方法。在本例中,这个对象就是从工厂获得的concretecomponent对象。通过将此装饰对象传递给decorator的一个类变量,你可以访问decorator中的任何方法。这就使你得以改变对象的状态了。
  
  图1中的decorator类不一定是接口或抽象类。如果你的程序不是很复杂,你可以将其转化为一个具体的decorator类。
  
  举个例子,考虑这样一个简单的消息传递程序,其主要部分是messenger接口及其实现类messengerimpl。让我们假设messengerimpl对象来自于一个工厂,因此你不能改变其状态。如果你准备增加或改变messenger对象的功能,你可以创建一个messengerdecorator类。图2是此例子的类图。
  
 关于装饰servlet request对象简介图(图二)

  
图2:messenger装饰类

  
  我们来看程序的代码。列表1给出了messenger接口的代码,列表2是messengerimpl类的代码。
  
  列表1:messenger接口
  
  public interface messenger { public string getmessage();}
  
  列表2:messengerimpl类
  
  public class messengerimpl implements messenger { private string message;
  public messengerimpl(string message) {  this.message = message;
  } public string getmessage() {  return message;
  }
  }
  
  messenger对象由一个名为messengerfactory的工厂创建,如列表3所示。
  
  列表3:messengerfactory类
  
  public class messengerfactory {
  public static messenger getmessenger()
  {
  return new messengerimpl("secrets");
  }
  }
  
  对每一个所创建的messenger对象,此工厂通过某个未知的操作,初始化了getmessage()方法所返回的字符串。换句话说,你不能自己创建messenger对象。
  
  在程序中,messenger对象的主要用途是被传递给一个名为util的类中的broadcast()静态方法。列表4是util类的代码。
  
  列表4:util类
  
  public class util {
  public static void broadcast(messenger messenger) {
  system.out.print(messenger.getmessage());
  }
  // other methods here}
  
  在你自己的类中,你可能会有这样的代码:
  
  messenger messenger = messengerfactory.getmessenger();
  util.broadcast(messenger);
  
  假设你希望对broadcast()方法所打印出的消息做一小改动。你拟将其转为大写,怎么做?表面上看,你可以继承messenger,实例化其子类,并将返回的对象传给util.broadcast()。但是,这种做法毫无意义,因为只有工厂才知道如何初始化messenger对象,并通过其getmessage()方法返回正确的值。
  
  使用装饰模式,你可以创建一个messengerdecorator类,如列表5所示。
  
  列表5:messengerdecorator类
  
  public class messengerdecorator implements messenger { private messenger messenger;
  public messengerdecorator(messenger messenger) {  this.messenger = messenger;
  } public string getmessage() {  return messenger.getmessage().touppercase();
  }
  }
  
  因为messengerdecorator实现了messenger,util.broadcast()将接受一个messengerdecorator的实例。然而,messengerdecorator不仅仅是一个接口的实现,它还是一个messengerimpl对象的装饰器。正因如此,messengerdecorator就必须有一个接收拟被装饰的messenger对象的构造方法。
  
  如列表5所示,这个构造方法将参数传给变量。你现在可以覆盖messengerdecorator中的getmessage()方法,以便将消息转为大写后再打印出来。因为你持有原来messenger对象的引用,你可以这样写getmessage()方法:
  
  public string getmessage() {
  return this.messenger.getmessage().touppercase();
  }
  
  messengerdecorator中的getmessage()方法返回原始消息的大写版本。
  
  在你的类中,就像往常一样,你得到一个messenger对象,并将decorator传给util.broadcast()。
  
  messenger messenger = factory.getmessenger();
  util.broadcast(new messengerdecorator(messenger));
  
  你并不将原始对象传给原先的目标,相反,你将其传给了该对象的装饰器。
  
  应用装饰模式于servlet
  
  以上messenger类的例子与servlet容器所构造的servletrequest对象是一样的。当收到一个http请求时,servlet容器就会创建servletrequest对象及servletresponse对象(分别是servletrequestimpl及servletresponseimpl的实例),并将这两个对象传递给特定的servlet服务方法。现在,如果你为servletrequest创建一个装饰角色,并将其传给servlet服务方法,你就应用了装饰模式。
  
  对servletrequest很容易应用装饰模式,因为servlet api已经为其提供了一个包装类:servletrequestwrapper。图3是一个servlet装饰模式的类图。
  
 关于装饰servlet request对象简介图(图三)

  
图3:servlet api中的装饰模式

  
  图3中的http版本的类图如图4所示。别为过多的类搞晕了头,只管注意虚线框中的三个类就行了:httpservletrequest, httpservletrequestimpl, httpservletrequestwrapper。
  
关于装饰servlet request对象简介图(图四)

  
图4:servlet api (http)的装饰模式

  
  情况与前面所举例子类似。你拥有一个servletrequest的实现,而它是由servlet容器产生的。你可以使用所提供的servletrequestwrapper来装饰这些servletrequest对象。
  
  这个模式很简单,在实际应用中可以派上用场。实际上,一些很有名的应用就使用了此模式。这些应用包括:
  
  struts - struts是当前开发java web应用最受欢迎的基于mvc(模型-视图-控制)模式的框架。struts提供了相当于servletrequest包装类的org.apache.struts.upload.multipartrequestwrapper类。 multipartrequestwrapper覆盖了getparameter(),getparameternames(),及getparametervalues()等方法来实现文件上传。
  
  apache beehive ?c 这个源于bea的weblogic专题小组的开源项目,构建于struts之上,并简化了web应用及web服务的开发。与servletrequest包装类一样,org.apache.beehive.netui.pageflow.internal包中的pageflowrequestw
 
 
上一篇: servlet和javaserverpages的集成应用    下一篇: 详解如何利用itext在jsp中生成pdf报表
  相关文档
如何使用动态代理实现aop功能 11-17
现在应该考 scjp 1.2 还是 scjp 1.4? 11-17
使用jsp的自定义标签开发 11-16
java对domino objects的访问 (5) 11-17
完整图解 tomcat 5.0.28 安装笔记 11-16
如何避免microsoft非标准javasdk的潜在危险(1) 11-17
使用netbeans 的五大理由 11-17
java socket编程(三) 服务器sockets 11-16
corba 及java idl应用编程 11-17
java标准单元测试库 junit 4 抢先看 11-17
java应用问答 11-17
论j2ee程序员的武功修为 11-17
java高级:讨论ajax之所以优于jsf的原因 11-16
用java插件在浏览器中运行java2 applet 11-17
在 java 应用程序中创建图像 11-17
java硬件 11-17
学习javabean 11-17
java高级--hibernate映射的基本操作 11-16
教程——漫谈java程序设计中的接口应用 11-17
一个简单的代理服务器 11-17
返回首页 | 关于我们 | J网章程 | JSP空间合租 | 客服中心 | 免责声明 | 常见问题 | 参观机房
本站主机空间代理至厦门市华众网络科技有限公司
《中华人民共和国增值电信业务经营许可证》
编号:闽B2-20050079
@2005-2008福建JSP技术网 版权所有 闽ICP备05000928号
厦门(总部):13616026886 福州:0591-87655121
邮箱:admin@fjjsp.com 站长QQ,点击这里给我发消息