什么是模板方法呢?我们先回想以下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教程