Struts2 中的设计模式

1. Command Pattern

基本定义: 把Command(Request)封装成对象,把发出命令(Invoker)的责任和执行命令(Receiver)的责任分割开,委派给不同的对象。

责任划分有什么好处?

责任约单一,内聚性越高,可重用的可能性越大,试想下,如果服务员不仅要点菜,还要去做菜,会是什么情景。

为什么把Invoker和Receiver解耦好处多?

类之间的耦合越低,可扩展的可能性越高。解耦后,更换一个服务员并不会影响厨师的工作

那么把Request封装成对象具体是什么意思呢?

在遥控器Remote Control例子中,比如我有一个‘开灯’的Request,那么就应该对应有一个LightOnCommand对象,关灯就应该有LightOffCommand

在Web应用中,我有一个add user的Request,那么就应有一个AddUserCommand去处理请求, 或者用struts的name convention就是AddUserAction.

那么在Struts中又是怎么运用Command Pattern的呢?

Client : FilterDispatcher Servlet

Invoker: ActionInvocation

Command: Action (not a must in Struts2)

ConcreteCommand:AddUserAction

Receiver: AddUserServiceImpl (not a must, depends on how many logic you want to put into concreteCommand)

Struts,你什么时候调用的setCommand()?

用户定义了Action Mapping在struts.xml里,在web container启动时,ConfigurationManager 就装载了struts.xml,当Request过来时,Struts Framework会根据当前的URL去找ConfigurationManager所对应的concreteCommand/Action,
然后这个Action会被set到ActionInvocation

Command Interface是必须的吗?

在struts1中,有一个Interface,所有的Action都必须是它的实现。但是在Struts2中,Action可以是任意的POJO,因为在Runtime的时候,具体的Action是什么,该调用它的什么方法,都可以通过配置文件(MetaData)+ Java Reflection来实现。这种新方式的好处是POJO
Action没有了对框架的依赖,测试将会更加容易。缺点是因为没有interface的约束,调用Action的什么方法完全取决于默认值(比如execute)或是配置文件中的配置。若设置不妥,只有在Runtime的时候才能发现错误。

Receiver 是必须得吗?

不是,取决于你Action的厚度,如果你想让Action很轻的话,那么通常你会在Action中使用UserService.addUser()去做事情,此时的UserService就是Receiver。把Action设计的厚点,直接把addUser的logic放在Action中也是可以的。

Struts2中运用了command的思想,但并没有严格的按照其经典模型实现,而是做了些变通,这些变通乍看起来可能是有点违背设计原则,比如说取消了Action Interface,这不是反模式吗,反面向接口的编程吗,但仔细想想,这里我们真的需要这个接口吗?通过配置文件+Reflection,我们同样可以做到在Runtime的时候给ActionInvocation注入不同的Action的目的。而接口却增加了用户实现对框架的依赖,降低了程序的可测性,所以这样的变通其实是有积极意义的,虽然我们损失了一点点接口作为契约所带来的好处。

2. Interceptor Pattern

于其说这是模式,不如说这是AOP和Pipeline思想的结合,只不过Struts2中的实现非常的精巧,我不得不说这应该作为一个模式来推广。

AOP: 所谓的AOP就是preProcess and postProcess, 系统应用中,许多地方是需要面向切面的,比如log,authentication,etc...。Java Dynamic Proxy通常也是实现AOP的方式,但它是通过Java Reflection的机制,动态的产生一个被修改过的method,从而达到预处理和后处理的目的,个人觉得这种方式粗暴不够优雅,并且可扩展性不好。
不过其优点是它是内嵌在JDK中的AOP,使用比较方面,对于那些不需要扩展性的需求,动态代理也是可以考虑的。

Pipeline:分层就是把复杂的问题分层多个层次,每一层只处理问题的一小部分。通信的7层模型就是典型的范例

Interceptor Pattern: 不仅为系统进行分层,而且还提供了AOP的处理,此外,还以一种plug-in的方式为用户提供了无限扩展的可能。

应该怎么实现?

Interceptor的调用过程类似于一个栈式调用,所以想到递归是很自然的,这既避免了像Dynamic Proxy那样的class hack,又提供了更好的扩展性。

 还是以Struts中的类作为例子,其类图如下:

调用过程:

Pseudo 代码:

ActionInvocation

public Result invoke(){
    if( interceptors.hasNext() ){
        Interceptor interceptor = interceptors.next();
        result = interceptor.intercept(this);
    }
    else {
        action.execute();//如果没有更多的Interceptor,停止递归,调用action
    }
}

InterceptorImpl

public SomeInterceptor implements Interceptor{
    public Result intercept(ActionInvocation actionInvocation){
       //pre-processing

        // 递归调用
        result = actionInvocation.invoke();

       //post-processing

       return result;
    }
}

More: http://www.cnblogs.com/west-link/archive/2011/06/22/2086591.html

http://bosy.dailydev.org/2007/04/interceptor-design-pattern.html

Struts2 架构图

Struts 2 framework: http://viralpatel.net/blogs/introduction-to-struts-2-framework/

时间: 2024-09-20 19:56:38

Struts2 中的设计模式的相关文章

请教,Struts2 中对数据库连接使用单例模式

问题描述 我的同事设计了在Struts2中对数据库连接使用单例模式,我问他如果连接只有一个实例,多用户下怎么办:他说Struts2可以确保多线程,我不太懂,这样设计行吗?程序如下:public class DatabaseInteraction { private static Statement m_statement; private static Connection m_connection; private boolean m_stateConnection = false; priv

struts2中页面表示国际化的方法

在struts2中,前端页面表示国际化的实现更加简单.简单的应用struts2提供的支持国际化的表达式 即可快速方便的进行页面的国际化的实现.如何做呢?本文以英文和中文为例进行说明. 1,自定义struts2的属性, 属性项目:struts.custom.i18n.resources 首先生成一个struts.properties文件, 文件位置:WEB-INF/src目录下 文件内容: struts.custom.i18n.resources=globalMessages 2,根据属性所指定的

struts2中action和field级别错误处理

在struts2中,一般的action都继承ActionSupport这个类,可以重写public void validate()来进行数据校验,对应提示信息来说一般有两个比较常用的方法就是this.addFieldError("field name","error message"); 和 this.addActionError("error message");两个方法. 由于在ActionSupport这个类实现了ValidationAwa

struts2中一个表单中提交多个请求的例子

  在很多Web应用中,为了完成不同的工作,一个HTML form标签中可能有两个或多个submit按钮,Struts2中提供了另外一种方法,使得无需要配置可以在同一个action类中执行不同的方法(默认执行的是execute方法) 使用这种方式也需要通过请求参来来指定要执行的动作.请求参数名的格式为 action!method.action 注:由于Struts2只需要参数名,因此,参数值是什么都可以. 下面我就给出一个实例程序来演示如何处理有多个submit的form: 主页面more_su

Struts2中Action接收参数的方法

Struts2中Action接收参数的方法主要有以下三种: 1.使用Action的属性接收参数:     a.定义:在Action类中定义属性,创建get和set方法:     b.接收:通过属性接收参数,如:userName:     c.发送:使用属性名传递参数,如:user1!add?userName=Magci: 2.使用DomainModel接收参数:     a.定义:定义Model类,在Action中定义Model类的对象(不需要new),创建该对象的get和set方法:    

[Head First设计模式]饺子馆(冬至)中的设计模式——工厂模式

[Head First设计模式]山西面馆中的设计模式--装饰者模式 [Head First设计模式]山西面馆中的设计模式--观察者模式 [Head First设计模式]山西面馆中的设计模式--建造者模式 引言 今天是冬至,去饺子馆吃饺子,看他们店里面的水饺种类挺多,在等待中,在想是不是可以用设计模式模拟一下,生产饺子的过程,正好最近也在看工厂模式,也就现学现卖了.当然,实现的方式很多,只是一个例子而已.祝大家冬至,多多吃水饺..... 对象创建的问题? 我们应该面向接口编程而不是面向实现编程,因

标签-struts2中,jsp页面设置theme="ajax"

问题描述 struts2中,jsp页面设置theme="ajax" <%@ page language=""java"" contentType=""text/html; charset=UTF-8"" pageEncoding=""UTF-8""%><!DOCTYPE html PUBLIC ""-//W3C//DTD HTML

Js显示Struts2中的内容之escape和escapeHtml

  $(function (){        var msg = '<s:property value="msg" escape="false"/>';        if(""!=msg)        {            alert(msg);        }    });   问题:Struts2 中后台属性值带有的HTML标签,前台页面取值时把HTML标签当成字符串输出了,怎么把它们当成HTML标签处理. 举个例子来

struts2中访问指定了方法,但是却把action下所有的方法都执行了一次这是怎么回事啊

问题描述 struts2中访问指定了方法,但是却把action下所有的方法都执行了一次这是怎么回事啊 具体配置如下图 xml配置如下: jsp如下: action如下: 解决方案 你的BaseAction是自定义的吧,还是哪个别的第三方包的,常用的是继承struct自带的MappingDispatchAction,这个是和struct.xml搭配来用,你也可以继承MappingDispatchAction这个类,然后再写你的action模式 解决方案二: 那应该就是你调用的函数getByPage