什么是模板方法呢?我們先回想以下SQL保存的例子,這個例子要 求我們能夠同時處理三種類型的SQL語句保存文件:XML格式的文件,Properties格式文件和普通的文本格式的文件。不論那種格式的文件都要求能 夠提供根據SQL語句名字獲得SQL語句的方法。我們可以這樣子設計:

public class AbstractSqlManager {

     private Map sqlMap ;

     public AbstractSqlManager(String filePath) {

         sqlMap = initSqlMap(filePath)

     }

     

     public String getSql(String key) {

         return (String)sqlMap.get(key);

     } 

     

     public abstract Map initSqlMap(String filePath);

 

public class XmlSqlManager extends AbstractSqlMamager {

     public Map initSqlMap(String filePath) {

         // 解析XML文件將SQL語句,以SQL語句的名字為Key,放在sqlMap中。

      }

}

 

public class PropertiesSqlManager extends AbstractSqlMamager {

     public Map initSqlMap(String filePath) {

         // 解析Properties文件將SQL語句,以SQL語句的名字為Key,放在sqlMap中。

      }

}

public class TextSqlManager extends AbstractSqlMamager {

     public Map initSqlMap(String filePath) {

         // 解析Text文件將SQL語句,以SQL語句的名字為Key,放在sqlMap中。

      }

}

 

參看上述的代碼,在AbstractSqlManager 中,因為可能處理的文件的內容不同,所以將解析不同代碼的方法實現放在了具體的類(XmlSqlManager ,PropertiesSqlManager 和TextSqlManager )中,只在AbstractSqlManager中實現了getSql方法。

 

我們在來考慮三個具體的實現類,在這些類實現的時候,需要從AbstractSqlManager集成,所以必須實現initSqlMap這個方法,并且必須按照AbstractSqlManager中定義的格式(模板)來實現。

 

這樣可以稱initSqlMap為模板方法,也可以稱上述的設計為模板方法。

 

模板方法設計的好處有那些呢?

第一,也是繼承的好處,可以重用代碼

     如上述的例子,使用了模板方法之后,可以將公共的方法和流程在基類中編寫,這樣可以重用這些代碼。(關于繼承和組合重用代碼的問題參看另外的相關討論)

第二,可以靈活的對應變更

     因為使用了模板方法,所以相同的操作可以在基類中 完成,具體的不同實現可以在具體類中完成。所以首先有了變更修改的范圍很容易確定,如果是通用的操作則需要在基類中完成,例如initSqlMap之前需 要使用日志記錄文件的信息。如果是特殊的操作則需要在具體類中完成,例如XML文件格式發生了變更。

     

第三,規范處理流程(例如有三個模板方法)

     使用模板方法可以規范處理流程,例如要對輸入的數進行相關的操作,我們可以定義這樣的幾個過程,(1)數據格式校驗(2)數據邏輯校驗(3)預處理(4)處理(5)處理輸出值(6)結束

     我們可以定義這樣子一個基類,包含需要的模板方法:

public class BaseTarget{

     public void execute(InputVO vo) throw ExecuteException {

         try {

                 formatCheck(vo);

                 logicCheck(vo);

                 preProcess(vo);

                 OutputVO out = process(vo);

                 formatCheck(out);

 

         } catch(FormatException ex) {

             // 異常處理

         } catch(LogicException ex) {

             // 異常處理 

         } catch(PreProcessExceptionex) {

              // 異常處理

         } catch(ProcessExceptionex) {

              // 異常處理

         } catch(PostProcessExceptionex) {

              // 異常處理

         } 

     }

 

     public abstract void formatCheck(InputVO vo) throw FormatException ;

 

     public abstract void logicCheck(InputVO vo) throw LogicException ;

 

     public abstract void preProcess(InputVO vo) throw PreProcessException;

 

     public abstract OutputVO process(InputVO vo) throw ProcessException;

 

     public abstract void postProcess(OutputVO vo) throw PostProcessException;

}

 

通過上述基類的定義,我們規定了子類型的處理內容(五個需要實現的抽象方法)和處理的順序(按照execute方法定義的處理順序執行)。

 



ExtJS教程- Hibernate教程-Struts2 教程-Lucene教程