春風博客

          春天里,百花香...

          導航

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

          統(tǒng)計

          公告

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

          Locations of visitors to this page

          常用鏈接

          留言簿(11)

          隨筆分類(224)

          隨筆檔案(126)

          個人軟件下載

          我的其它博客

          我的鄰居們

          最新隨筆

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          使用模板方法模式簡化控制層類(Action)的設計

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

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

          具體請參考以下代碼:

          諸Action的基類,包含了所有的異常處理,它是一個抽象類,規(guī)定子類必需實現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中找不到用戶,要執(zhí)行操作請先登錄");            
                      
          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){
                      
          // 系統(tǒng)發(fā)生重大問題,一個用戶名對應著多條記錄
                      request.setAttribute("feedbackTitle""系統(tǒng)發(fā)生重大問題");
                      request.setAttribute(
          "feedbackConcept""系統(tǒng)發(fā)生重大問題,成員用戶名對應著多條記錄,報告此錯誤的郵件已經發(fā)給系統(tǒng)管理員,請耐心等候處理。");
                      
          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");
                  }

              }

              
              
          /**
               * 留待子類實現業(yè)務
               * 
          @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");
              }

          }

          這樣完成以后,對子類來說,只需要關心業(yè)務代碼即可,出現異常后的處理和轉向都由基類規(guī)定的模板方法完成,這正是模板方法模式給我們帶來的好處。有點疑惑的是,現在還不確定這樣做會有什么消極印象,如安全性或結構方面的,大家要是覺得有問題請不吝賜教。

          posted on 2008-09-01 11:51 sitinspring 閱讀(2215) 評論(8)  編輯  收藏 所屬分類: Object Orient Programming 、SSH

          評論

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

          更多的公共代碼的放置問題,骨架突出的成份小  回復  更多評論   

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

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

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

          @隔葉黃鶯
          “尋道者”和你講的不是一個層面的問題?!皩さ勒摺敝v的是設計模式,你說的框架使用。你這么比,樓主有可能會生氣。

          @隔葉黃鶯
          也斗膽接著聊一下你說的那個問題。從抽象層面講,我們如果想要處理一個行為的變化,一般需要干這幾件事情:
          抽象變化,封裝變化
          數據上下文
          控制上下文

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

          我們再切換到另外一個角度來看這個問題,任何一個框架肯定就是提供可復用的數據和行為。這種異常處理的配置機制暫且看作框架提供的行為支持吧。 那我可能會問了?我一個業(yè)務處理過程本身就包含了異常處理,我干嗎再去配啊,而且給我分開了,以后還要維護這個配置文件???

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

          @隔葉黃鶯:我只是有興趣瞎評論一下,錯誤請指正  回復  更多評論   

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

          @zhuxing
          樓主代碼實際用到 Struts,我才說起 struts 框架來,以及它能提供給我們的便利

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

          當然,與業(yè)務非常密緊密的異常,可能放在統(tǒng)一異常處理類里不是很合適。不過要是考慮正常業(yè)務邏輯與異常流程分開來,丟給一個 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
          你的用語很職業(yè),只是我們需要切合這里的實際來討論問題。  回復  更多評論   

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

          @隔葉黃鶯
          哈哈。
          回到實際,樓主文章中說的主題和異常配置也有點遠,覺得樓主好像意在說一個設計模式
            回復  更多評論   

          sitinspring(http://www.aygfsteel.com)原創(chuàng),轉載請注明出處.
          主站蜘蛛池模板: 密云县| 湾仔区| 齐齐哈尔市| 巴林右旗| 清水县| 西贡区| 大关县| 天全县| 依兰县| 泽普县| 衢州市| 交口县| 上饶市| 尼木县| 昔阳县| 大埔县| 贵阳市| 天柱县| 明星| 宁武县| 开化县| 当涂县| 淮南市| 韶关市| 南平市| 岱山县| 英吉沙县| 玛曲县| 罗平县| 宜城市| 肃宁县| 绥江县| 桐庐县| 台南市| 樟树市| 竹北市| 郑州市| 乳源| 霍邱县| 莱芜市| 青河县|