春風(fēng)博客

          春天里,百花香...

          導(dǎo)航

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

          統(tǒng)計(jì)

          公告

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

          Locations of visitors to this page

          常用鏈接

          留言簿(11)

          隨筆分類(224)

          隨筆檔案(126)

          個(gè)人軟件下載

          我的其它博客

          我的鄰居們

          最新隨筆

          搜索

          積分與排名

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          使用模板方法模式簡(jiǎn)化控制層類(Action)的設(shè)計(jì)

          在基于Model2的應(yīng)用中,控制層的類總會(huì)包含對(duì)業(yè)務(wù)層諸類的調(diào)用,業(yè)務(wù)層諸類不可避免的要產(chǎn)生各種異常,如果統(tǒng)一到控制層進(jìn)行處理的話會(huì)導(dǎo)致代碼變得龐大臃腫還有不少重復(fù),這種的例子在Web應(yīng)用中的Servlet和Action諸類中并不少見。

          如果我們使用模板方法模式(Template Method Pattern)將業(yè)務(wù)處理和異常處理分開,能有效簡(jiǎn)化控制層諸類的代碼,借用這種模式,我們可以把固定的異常處理代碼放在基類中,而讓子類來(lái)實(shí)現(xiàn)具體的業(yè)務(wù),如果執(zhí)行業(yè)務(wù)過(guò)程中出現(xiàn)異常如數(shù)據(jù)庫(kù)無(wú)法連接,用戶找不到等異常后,直接將異常拋出讓基類來(lái)處理,這樣做成功的把業(yè)務(wù)處理和異常處理分開到了子類和基類兩種類中,涉及具體業(yè)務(wù)處理的子類代碼得到了很大的簡(jiǎn)化,更方便閱讀,修改和管理。

          具體請(qǐng)參考以下代碼:

          諸Action的基類,包含了所有的異常處理,它是一個(gè)抽象類,規(guī)定子類必需實(shí)現(xiàn)process函數(shù):
          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;

          /**
           * 各個(gè)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中找不到用戶,要執(zhí)行操作請(qǐng)先登錄");            
                      
          return new ActionForward("/web/page/login.jsp");
                  }
           
                  
          catch(CannotFindRecordByIdException ex){
                      
          // 用戶名不存在
                      request.setAttribute("msg""用戶名不存在,請(qǐng)重新輸入");            
                      
          return new ActionForward("/web/page/login.jsp");
                  }
            
                  
          catch(ErrorPswdException ex){
                      
          // 用戶登錄密碼錯(cuò)誤
                      request.setAttribute("msg""密碼錯(cuò)誤,請(qǐng)重新輸入");            
                      
          return new ActionForward("/web/page/login.jsp");
                  }

                  
          catch(OneIdMultiRecordException ex){
                      
          // 系統(tǒng)發(fā)生重大問(wèn)題,一個(gè)用戶名對(duì)應(yīng)著多條記錄
                      request.setAttribute("feedbackTitle""系統(tǒng)發(fā)生重大問(wèn)題");
                      request.setAttribute(
          "feedbackConcept""系統(tǒng)發(fā)生重大問(wèn)題,成員用戶名對(duì)應(yīng)著多條記錄,報(bào)告此錯(cuò)誤的郵件已經(jīng)發(fā)給系統(tǒng)管理員,請(qǐng)耐心等候處理。");
                      
          return new ActionForward("/web/page/result.jsp");
                  }
                    
                  
          catch(TypeMismatchDataAccessException ex){
                      request.setAttribute(
          "feedbackTitle""Java類型和數(shù)據(jù)類型不匹配.");
                      request.setAttribute(
          "feedbackConcept""錯(cuò)誤信息為"+ex.getMessage());
                      
          return new ActionForward("/web/page/result.jsp");
                  }

                  
          catch(DataAccessResourceFailureException ex){
                      request.setAttribute(
          "feedbackTitle""無(wú)法連接到數(shù)據(jù)庫(kù),請(qǐng)檢查數(shù)據(jù)庫(kù)連接是否正確.");
                      request.setAttribute(
          "feedbackConcept""錯(cuò)誤信息為"+ex.getMessage());
                      
          return new ActionForward("/web/page/result.jsp");
                  }

                  
          catch(DataIntegrityViolationException ex){
                      request.setAttribute(
          "feedbackTitle""Insert或Update數(shù)據(jù)時(shí)違反了完整性.");
                      request.setAttribute(
          "feedbackConcept""錯(cuò)誤信息為"+ex.getMessage());
                      
          return new ActionForward("/web/page/result.jsp");
                  }

                  
          catch(InvalidDataAccessResourceUsageException ex){
                      request.setAttribute(
          "feedbackTitle""使用錯(cuò)誤的SQL語(yǔ)句或數(shù)據(jù)訪問(wèn)關(guān)系型數(shù)據(jù)庫(kù).");
                      request.setAttribute(
          "feedbackConcept""錯(cuò)誤信息為"+ex.getMessage());
                      
          return new ActionForward("/web/page/result.jsp");
                  }

                  
          catch(Exception ex){
                      request.setAttribute(
          "feedbackTitle""未知的錯(cuò)誤");
                      request.setAttribute(
          "feedbackConcept""錯(cuò)誤信息為"+ex.getMessage());
                      
          return new ActionForward("/web/page/result.jsp");
                  }

              }

              
              
          /**
               * 留待子類實(shí)現(xiàn)業(yè)務(wù)
               * 
          @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,只需實(shí)現(xiàn)簡(jiǎn)短的process函數(shù)即可,所有異常拋出由基類處理:
          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");
                  
                  
          // 取得參數(shù)
                  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");
              }

          }

          這樣完成以后,對(duì)子類來(lái)說(shuō),只需要關(guān)心業(yè)務(wù)代碼即可,出現(xiàn)異常后的處理和轉(zhuǎn)向都由基類規(guī)定的模板方法完成,這正是模板方法模式給我們帶來(lái)的好處。有點(diǎn)疑惑的是,現(xiàn)在還不確定這樣做會(huì)有什么消極印象,如安全性或結(jié)構(gòu)方面的,大家要是覺(jué)得有問(wèn)題請(qǐng)不吝賜教。

          posted on 2008-09-01 11:51 sitinspring 閱讀(2219) 評(píng)論(8)  編輯  收藏 所屬分類: Object Orient ProgrammingSSH

          評(píng)論

          # re: 使用模板方法模式簡(jiǎn)化控制層類(Action)的設(shè)計(jì) 2008-09-01 14:14 zhuxing

          更多的公共代碼的放置問(wèn)題,骨架突出的成份小  回復(fù)  更多評(píng)論   

          # re: 使用模板方法模式簡(jiǎn)化控制層類(Action)的設(shè)計(jì) 2008-09-01 14:38 隔葉黃鶯

          現(xiàn)在流行的MVC框架,如 Struts1/Struts2/WebWork/Spring MVC 都能以配置的方式來(lái)處理異常,也不需在基類 Action 中處理。
          你的 Action 執(zhí)行方法只需往框架拋異常,配置一個(gè) ExeptionHandler 就會(huì)處理控制層拋出的異常,這樣的做法讓控制層和異常處理類解耦。
          不像你的 BaseAction 實(shí)際與異常處理綁定到一起了,我原來(lái)的項(xiàng)目也是會(huì)寫這么一個(gè) BaseAction,后來(lái)更細(xì)致了解一下所用的框架就會(huì)單獨(dú)寫一個(gè)異常處理類,配置給框架。  回復(fù)  更多評(píng)論   

          # re: 使用模板方法模式簡(jiǎn)化控制層類(Action)的設(shè)計(jì) 2008-09-01 15:04 zhuxing

          @隔葉黃鶯
          “尋道者”和你講的不是一個(gè)層面的問(wèn)題。“尋道者”講的是設(shè)計(jì)模式,你說(shuō)的框架使用。你這么比,樓主有可能會(huì)生氣。

          @隔葉黃鶯
          也斗膽接著聊一下你說(shuō)的那個(gè)問(wèn)題。從抽象層面講,我們?nèi)绻胍幚硪粋€(gè)行為的變化,一般需要干這幾件事情:
          抽象變化,封裝變化
          數(shù)據(jù)上下文
          控制上下文

          這種流行框架中的異常處理配置機(jī)制就真的好嗎,如果用戶想進(jìn)行自定義的控制下文呢(例如摟主文中的)???如果數(shù)據(jù)上下文變化較為頻繁呢???(當(dāng)然,這可能是由于起初對(duì)需求抽象不夠,對(duì)已知擴(kuò)展沒(méi)有做詳細(xì)分析)

          我們?cè)偾袚Q到另外一個(gè)角度來(lái)看這個(gè)問(wèn)題,任何一個(gè)框架肯定就是提供可復(fù)用的數(shù)據(jù)和行為。這種異常處理的配置機(jī)制暫且看作框架提供的行為支持吧。 那我可能會(huì)問(wèn)了?我一個(gè)業(yè)務(wù)處理過(guò)程本身就包含了異常處理,我干嗎再去配啊,而且給我分開了,以后還要維護(hù)這個(gè)配置文件???

          這種異常配置的機(jī)制有它的好處,也有它的適用場(chǎng)景,再一個(gè)那就是取決于開發(fā)者的嗜好....

          @隔葉黃鶯:我只是有興趣瞎評(píng)論一下,錯(cuò)誤請(qǐng)指正  回復(fù)  更多評(píng)論   

          # re: 使用模板方法模式簡(jiǎn)化控制層類(Action)的設(shè)計(jì) 2008-09-01 15:33 隔葉黃鶯

          @zhuxing
          樓主代碼實(shí)際用到 Struts,我才說(shuō)起 struts 框架來(lái),以及它能提供給我們的便利

          看樓主的基類 Action 其實(shí)是包含了多種業(yè)務(wù)的異常處理,作為樓主的替代方式,應(yīng)該配置一個(gè)異常處理類即可,不需要配置多個(gè),所以不涉及到要怎么去維護(hù)這個(gè)配置文件。如果分業(yè)務(wù)定義多個(gè)基類 Action 來(lái)處理異常,又何異于配置多個(gè)異常處理類呢?

          當(dāng)然,與業(yè)務(wù)非常密緊密的異常,可能放在統(tǒng)一異常處理類里不是很合適。不過(guò)要是考慮正常業(yè)務(wù)邏輯與異常流程分開來(lái),丟給一個(gè) ExceptionHandler 也未嘗不可。

          如果數(shù)據(jù)上下文變化較為頻繁呢,這時(shí)候就要修改基類 Action 處理異常的代碼,這和修改異常處理類也沒(méi)多少分別。
            回復(fù)  更多評(píng)論   

          # re: 使用模板方法模式簡(jiǎn)化控制層類(Action)的設(shè)計(jì) 2008-09-01 15:50 尋道者

          @zhuxing
          @隔葉黃鶯

          兩位都談得很好啊,受益匪淺,本來(lái)我寫這個(gè)文章就是為了討論和驗(yàn)證想法的。只要是技術(shù)討論,大家暢所欲言吧。

            回復(fù)  更多評(píng)論   

          # re: 使用模板方法模式簡(jiǎn)化控制層類(Action)的設(shè)計(jì) 2008-09-01 16:12 zhuxing

          @隔葉黃鶯 @尋道者

          一個(gè)框架給我們提供了服務(wù)的同時(shí),肯定會(huì)給我們提供了相應(yīng)的限制。我覺(jué)得,很多時(shí)候在決定要使用一個(gè)開源框架或者新的方法論(例如AOP)的時(shí)候,不但要看到框架的作用,也需要投入很大精力來(lái)分析一下框架的短板和限制。當(dāng)然,是基于我們的需求來(lái)分析,如果脫離這一點(diǎn),那就沒(méi)有意義了,純技術(shù)去分析一個(gè)框架可以當(dāng)作閑來(lái)無(wú)事時(shí)的消遣~_~  回復(fù)  更多評(píng)論   

          # re: 使用模板方法模式簡(jiǎn)化控制層類(Action)的設(shè)計(jì) 2008-09-01 17:46 隔葉黃鶯

          @zhuxing
          你的用語(yǔ)很職業(yè),只是我們需要切合這里的實(shí)際來(lái)討論問(wèn)題。  回復(fù)  更多評(píng)論   

          # re: 使用模板方法模式簡(jiǎn)化控制層類(Action)的設(shè)計(jì) 2008-09-01 18:03 zhuxing

          @隔葉黃鶯
          哈哈。
          回到實(shí)際,樓主文章中說(shuō)的主題和異常配置也有點(diǎn)遠(yuǎn),覺(jué)得樓主好像意在說(shuō)一個(gè)設(shè)計(jì)模式
            回復(fù)  更多評(píng)論   

          sitinspring(http://www.aygfsteel.com)原創(chuàng),轉(zhuǎn)載請(qǐng)注明出處.
          主站蜘蛛池模板: 安义县| 大悟县| 宝清县| 修水县| 呼玛县| 育儿| 雅安市| 巴马| 夏津县| 海丰县| 沙雅县| 镶黄旗| 新建县| 泰兴市| 太湖县| 苏州市| 葫芦岛市| 青阳县| 尚义县| 罗平县| 巴中市| 绍兴市| 湘西| 成都市| 哈尔滨市| 桑日县| 冷水江市| 河曲县| 洪湖市| 峨眉山市| 清苑县| 潼南县| 彝良县| 乌兰浩特市| 金寨县| 新安县| 中牟县| 高青县| 东安县| 上林县| 垫江县|