春风博客

春天里,百花香...

导航

<2008年9月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

统计

公告

MAIL: junglesong@gmail.com
MSN: junglesong_5@hotmail.com

Locations of visitors to this page

常用链接

留言簿(11)

随笔分类(224)

随笔档案(126)

个人软件下载

我的其它博客

我的邻居们

最新随笔

搜索

积分与排名

最新评论

阅读排行榜

评论排行榜

使用模板方法模式简化控制层类(Action)的设计

在基于Model2的应用中,控制层的类总会包含对业务层诸类的调用,业务层诸类不可避免的要产生各种异常,如果统一到控制层进行处理的话会导致代码变得庞大臃肿还有不少重复,这种的例子在Web应用中的Servlet和Action诸类中并不少见。

如果我们使用模板方法模式(Template Method Pattern)将业务处理和异常处理分开,能有效简化控制层诸类的代码,借用这种模式,我们可以把固定的异常处理代码放在基类中,而让子类来实现具体的业务,如果执行业务过程中出现异常如数据库无法连接,用户找不到等异常后,直接将异常抛出让基类来处理,这样做成功的把业务处理和异常处理分开到了子类和基类两种类中,涉及具体业务处理的子类代码得到了很大的简化,更方便阅读,修改和管理。

具体请参考以下代码:

诸Action的基类,包含了所有的异常处理,它是一个抽象类,规定子类必需实现process函数:
package com.heyang.action.base;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.dao.TypeMismatchDataAccessException;

import com.heyang.domain.User;
import com.heyang.exception.database.CannotFindRecordByIdException;
import com.heyang.exception.database.OneIdMultiRecordException;
import com.heyang.exception.user.CannotFindUserInSessionException;
import com.heyang.exception.user.ErrorPswdException;

/**
 * 各个Action的基类
 * 
@author 何杨(heyang78@gmail.com)
 *
 * 
@since 2008-8-29 上午09:00:48
 * 
@version 1.00
 
*/

public abstract class BizBaseAction extends Action {
    
public ActionForward execute(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
            
throws Exception {
        
        request.setCharacterEncoding(
"UTF-8");
                
        
try{
            
return process(mapping,form,request,response);
        }

        
catch(CannotFindUserInSessionException ex){
            
// 用户名不存在
            request.setAttribute("msg""在session中找不到用户,要执行操作请先登录");            
            
return new ActionForward("/web/page/login.jsp");
        }
 
        
catch(CannotFindRecordByIdException ex){
            
// 用户名不存在
            request.setAttribute("msg""用户名不存在,请重新输入");            
            
return new ActionForward("/web/page/login.jsp");
        }
  
        
catch(ErrorPswdException ex){
            
// 用户登录密码错误
            request.setAttribute("msg""密码错误,请重新输入");            
            
return new ActionForward("/web/page/login.jsp");
        }

        
catch(OneIdMultiRecordException ex){
            
// 系统发生重大问题,一个用户名对应着多条记录
            request.setAttribute("feedbackTitle""系统发生重大问题");
            request.setAttribute(
"feedbackConcept""系统发生重大问题,成员用户名对应着多条记录,报告此错误的邮件已经发给系统管理员,请耐心等候处理。");
            
return new ActionForward("/web/page/result.jsp");
        }
          
        
catch(TypeMismatchDataAccessException ex){
            request.setAttribute(
"feedbackTitle""Java类型和数据类型不匹配.");
            request.setAttribute(
"feedbackConcept""错误信息为"+ex.getMessage());
            
return new ActionForward("/web/page/result.jsp");
        }

        
catch(DataAccessResourceFailureException ex){
            request.setAttribute(
"feedbackTitle""无法连接到数据库,请检查数据库连接是否正确.");
            request.setAttribute(
"feedbackConcept""错误信息为"+ex.getMessage());
            
return new ActionForward("/web/page/result.jsp");
        }

        
catch(DataIntegrityViolationException ex){
            request.setAttribute(
"feedbackTitle""Insert或Update数据时违反了完整性.");
            request.setAttribute(
"feedbackConcept""错误信息为"+ex.getMessage());
            
return new ActionForward("/web/page/result.jsp");
        }

        
catch(InvalidDataAccessResourceUsageException ex){
            request.setAttribute(
"feedbackTitle""使用错误的SQL语句或数据访问关系型数据库.");
            request.setAttribute(
"feedbackConcept""错误信息为"+ex.getMessage());
            
return new ActionForward("/web/page/result.jsp");
        }

        
catch(Exception ex){
            request.setAttribute(
"feedbackTitle""未知的错误");
            request.setAttribute(
"feedbackConcept""错误信息为"+ex.getMessage());
            
return new ActionForward("/web/page/result.jsp");
        }

    }

    
    
/**
     * 留待子类实现业务
     * 
@param mapping
     * 
@param form
     * 
@param request
     * 
@param response
     * 
@return
     * 
@throws Exception
     
*/

    
protected abstract ActionForward process(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
    
throws Exception ;

    
    
/**
     * 从Session中找出登录用户
     * 
@param request
     * 
@return
     * 
@throws CannotFindUserInSessionException
     
*/

    
protected User getUser(HttpServletRequest request) throws CannotFindUserInSessionException{
        
// 从Session中取得用户
        User user = (User) request.getSession().getAttribute("user");
        
if (user == null{
            
throw new CannotFindUserInSessionException("在session中找不到用户");
        }

        
        
return user;
    }

}


子类之一loginAction,只需实现简短的process函数即可,所有异常抛出由基类处理:
package com.heyang.action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import com.heyang.action.base.BizBaseAction;
import com.heyang.domain.User;
import com.heyang.service.UserService;
import com.heyang.util.ReqUtil;
import com.heyang.util.SpringUtil;

/**
 * 用于用户登录的Action
 * 
@author 何杨(heyang78@gmail.com)
 *
 * 
@since 2008-8-29 上午09:00:48
 * 
@version 1.00
 
*/

public final class LoginAction extends BizBaseAction {
    
public ActionForward process(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
            
throws Exception {
        request.setCharacterEncoding(
"UTF-8");
        
        
// 取得参数
        String name = ReqUtil.getFormProperty("name",form);
        String pswd 
= ReqUtil.getFormProperty("pswd",form);
            
        
// 取得Service
        UserService service=SpringUtil.getUserService();        
        
        
// 取得用户
        User user=service.getUser(name, pswd);
        request.getSession().setAttribute(
"user", user);
        
return new ActionForward("/ShowBlocks.do");
    }

}

这样完成以后,对子类来说,只需要关心业务代码即可,出现异常后的处理和转向都由基类规定的模板方法完成,这正是模板方法模式给我们带来的好处。有点疑惑的是,现在还不确定这样做会有什么消极印象,如安全性或结构方面的,大家要是觉得有问题请不吝赐教。

posted on 2008-09-01 11:51 sitinspring 阅读(2193) 评论(8)  编辑  收藏 所属分类: Object Orient ProgrammingSSH

评论

# re: 使用模板方法模式简化控制层类(Action)的设计 2008-09-01 14:14 zhuxing

更多的公共代码的放置问题,骨架突出的成份小  回复  更多评论   

# re: 使用模板方法模式简化控制层类(Action)的设计 2008-09-01 14:38 隔叶黄莺

现在流行的MVC框架,如 Struts1/Struts2/WebWork/Spring MVC 都能以配置的方式来处理异常,也不需在基类 Action 中处理。
你的 Action 执行方法只需往框架抛异常,配置一个 ExeptionHandler 就会处理控制层抛出的异常,这样的做法让控制层和异常处理类解耦。
不像你的 BaseAction 实际与异常处理绑定到一起了,我原来的项目也是会写这么一个 BaseAction,后来更细致了解一下所用的框架就会单独写一个异常处理类,配置给框架。  回复  更多评论   

# re: 使用模板方法模式简化控制层类(Action)的设计 2008-09-01 15:04 zhuxing

@隔叶黄莺
“寻道者”和你讲的不是一个层面的问题。“寻道者”讲的是设计模式,你说的框架使用。你这么比,楼主有可能会生气。

@隔叶黄莺
也斗胆接着聊一下你说的那个问题。从抽象层面讲,我们如果想要处理一个行为的变化,一般需要干这几件事情:
抽象变化,封装变化
数据上下文
控制上下文

这种流行框架中的异常处理配置机制就真的好吗,如果用户想进行自定义的控制下文呢(例如搂主文中的)???如果数据上下文变化较为频繁呢???(当然,这可能是由于起初对需求抽象不够,对已知扩展没有做详细分析)

我们再切换到另外一个角度来看这个问题,任何一个框架肯定就是提供可复用的数据和行为。这种异常处理的配置机制暂且看作框架提供的行为支持吧。 那我可能会问了?我一个业务处理过程本身就包含了异常处理,我干吗再去配啊,而且给我分开了,以后还要维护这个配置文件???

这种异常配置的机制有它的好处,也有它的适用场景,再一个那就是取决于开发者的嗜好....

@隔叶黄莺:我只是有兴趣瞎评论一下,错误请指正  回复  更多评论   

# re: 使用模板方法模式简化控制层类(Action)的设计 2008-09-01 15:33 隔叶黄莺

@zhuxing
楼主代码实际用到 Struts,我才说起 struts 框架来,以及它能提供给我们的便利

看楼主的基类 Action 其实是包含了多种业务的异常处理,作为楼主的替代方式,应该配置一个异常处理类即可,不需要配置多个,所以不涉及到要怎么去维护这个配置文件。如果分业务定义多个基类 Action 来处理异常,又何异于配置多个异常处理类呢?

当然,与业务非常密紧密的异常,可能放在统一异常处理类里不是很合适。不过要是考虑正常业务逻辑与异常流程分开来,丢给一个 ExceptionHandler 也未尝不可。

如果数据上下文变化较为频繁呢,这时候就要修改基类 Action 处理异常的代码,这和修改异常处理类也没多少分别。
  回复  更多评论   

# re: 使用模板方法模式简化控制层类(Action)的设计 2008-09-01 15:50 寻道者

@zhuxing
@隔叶黄莺

两位都谈得很好啊,受益匪浅,本来我写这个文章就是为了讨论和验证想法的。只要是技术讨论,大家畅所欲言吧。

  回复  更多评论   

# re: 使用模板方法模式简化控制层类(Action)的设计 2008-09-01 16:12 zhuxing

@隔叶黄莺 @寻道者

一个框架给我们提供了服务的同时,肯定会给我们提供了相应的限制。我觉得,很多时候在决定要使用一个开源框架或者新的方法论(例如AOP)的时候,不但要看到框架的作用,也需要投入很大精力来分析一下框架的短板和限制。当然,是基于我们的需求来分析,如果脱离这一点,那就没有意义了,纯技术去分析一个框架可以当作闲来无事时的消遣~_~  回复  更多评论   

# re: 使用模板方法模式简化控制层类(Action)的设计 2008-09-01 17:46 隔叶黄莺

@zhuxing
你的用语很职业,只是我们需要切合这里的实际来讨论问题。  回复  更多评论   

# re: 使用模板方法模式简化控制层类(Action)的设计 2008-09-01 18:03 zhuxing

@隔叶黄莺
哈哈。
回到实际,楼主文章中说的主题和异常配置也有点远,觉得楼主好像意在说一个设计模式
  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 
sitinspring(http://www.blogjava.net)原创,转载请注明出处.