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