什么是模板方法呢?我們先回想以下SQL保存的例子,這個(gè)例子要
求我們能夠同時(shí)處理三種類(lèi)型的SQL語(yǔ)句保存文件:XML格式的文件,Properties格式文件和普通的文本格式的文件。不論那種格式的文件都要求能
夠提供根據(jù)SQL語(yǔ)句名字獲得SQL語(yǔ)句的方法。我們可以這樣子設(shè)計(jì):
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語(yǔ)句,以SQL語(yǔ)句的名字為Key,放在sqlMap中。
}
}
public class PropertiesSqlManager extends AbstractSqlMamager {
public Map initSqlMap(String filePath) {
// 解析Properties文件將SQL語(yǔ)句,以SQL語(yǔ)句的名字為Key,放在sqlMap中。
}
}
public class TextSqlManager extends AbstractSqlMamager {
public Map initSqlMap(String filePath) {
// 解析Text文件將SQL語(yǔ)句,以SQL語(yǔ)句的名字為Key,放在sqlMap中。
}
}
參看上述的代碼,在AbstractSqlManager
中,因?yàn)榭赡芴幚淼奈募膬?nèi)容不同,所以將解析不同代碼的方法實(shí)現(xiàn)放在了具體的類(lèi)(XmlSqlManager
,PropertiesSqlManager 和TextSqlManager
)中,只在AbstractSqlManager中實(shí)現(xiàn)了getSql方法。
我們?cè)趤?lái)考慮三個(gè)具體的實(shí)現(xiàn)類(lèi),在這些類(lèi)實(shí)現(xiàn)的時(shí)候,需要從AbstractSqlManager集成,所以必須實(shí)現(xiàn)initSqlMap這個(gè)方法,并且必須按照AbstractSqlManager中定義的格式(模板)來(lái)實(shí)現(xiàn)。
這樣可以稱(chēng)initSqlMap為模板方法,也可以稱(chēng)上述的設(shè)計(jì)為模板方法。
模板方法設(shè)計(jì)的好處有那些呢?
第一,也是繼承的好處,可以重用代碼
如上述的例子,使用了模板方法之后,可以將公共的方法和流程在基類(lèi)中編寫(xiě),這樣可以重用這些代碼。(關(guān)于繼承和組合重用代碼的問(wèn)題參看另外的相關(guān)討論)
第二,可以靈活的對(duì)應(yīng)變更
因?yàn)槭褂昧四0宸椒ǎ韵嗤牟僮骺梢栽诨?lèi)中
完成,具體的不同實(shí)現(xiàn)可以在具體類(lèi)中完成。所以首先有了變更修改的范圍很容易確定,如果是通用的操作則需要在基類(lèi)中完成,例如initSqlMap之前需
要使用日志記錄文件的信息。如果是特殊的操作則需要在具體類(lèi)中完成,例如XML文件格式發(fā)生了變更。
第三,規(guī)范處理流程(例如有三個(gè)模板方法)
使用模板方法可以規(guī)范處理流程,例如要對(duì)輸入的數(shù)進(jìn)行相關(guān)的操作,我們可以定義這樣的幾個(gè)過(guò)程,(1)數(shù)據(jù)格式校驗(yàn)(2)數(shù)據(jù)邏輯校驗(yàn)(3)預(yù)處理(4)處理(5)處理輸出值(6)結(jié)束
我們可以定義這樣子一個(gè)基類(lèi),包含需要的模板方法:
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;
}
通過(guò)上述基類(lèi)的定義,我們規(guī)定了子類(lèi)型的處理內(nèi)容(五個(gè)需要實(shí)現(xiàn)的抽象方法)和處理的順序(按照execute方法定義的處理順序執(zhí)行)。
ExtJS教程-
Hibernate教程-
Struts2 教程-
Lucene教程