1.模版方法模式簡介
模版方法模式介紹
在軟件開發(fā)中,有時(shí)會(huì)遇到類似的情況,某個(gè)方法的實(shí)現(xiàn)需要多個(gè)步驟笙纤,其中有些步驟是固定的,而有些步驟并不固定组力,存在可變性省容。為了提高代碼的復(fù)用性和系統(tǒng)的靈活性,可以使用模板方法模式來應(yīng)對這類情況燎字。
模版方法模式定義
定義一個(gè)操作中的算法框架腥椒,而將一些步驟延遲到子類中阿宅,使得子類可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義算法的某些特定步驟。
模版方法模式結(jié)構(gòu)圖
- AbstractClass:抽象類笼蛛,定義了一套算法洒放。
- ConcreteClass:具體實(shí)現(xiàn)類。
2.模版方法模式的簡單實(shí)現(xiàn)
延續(xù)著上一篇設(shè)計(jì)模式(八)外觀模式的寫法滨砍,我們?nèi)耘f來舉一個(gè)武俠的例子往湿,原諒博主是一個(gè)武俠迷。
創(chuàng)建抽象類惋戏,定義算法框架
一個(gè)武俠要戰(zhàn)斗的時(shí)候领追,也有一套固定的通用模式,那就是運(yùn)行內(nèi)功响逢、開通經(jīng)脈绒窑、準(zhǔn)備武器和使用招式,我們把這些用代碼表示就是:
public abstract class AbstractSwordsman {
//該方法為final舔亭,防止算法框架被覆寫
public final void fighting(){
//運(yùn)行內(nèi)功些膨,抽象方法
neigong();
//調(diào)整經(jīng)脈,具體方法
meridian();
//如果有武器則準(zhǔn)備武器
if(hasWeapons()) {
weapons();
}
//使用招式
moves();
//鉤子方法
hook();
}
//空實(shí)現(xiàn)方法
protected void hook(){}
protected abstract void neigong();
protected abstract void weapons();
protected abstract void moves();
protected void meridian(){
System.out.println("開通正經(jīng)與奇經(jīng)");
}
/**
* 是否有武器,默認(rèn)是有武器的钦铺,鉤子方法
* @return
*/
protected boolean hasWeapons(){
return true;
}
}
需要注意的是這個(gè)抽象類包含了三種類型的方法订雾,分別是抽象方法、具體方法和鉤子方法矛洞。抽象方法是交由子類去實(shí)現(xiàn)葬燎,具體方法則在父類實(shí)現(xiàn)了子類公共的方法實(shí)現(xiàn),在上面的例子就是武俠開通經(jīng)脈的方式都一樣缚甩,所以就在具體方法中實(shí)現(xiàn)。鉤子方法則分為兩類窑邦,第一類是15行擅威,它有一個(gè)空實(shí)現(xiàn)的方法,子類可以視情況來決定是否要覆蓋它冈钦;第二類則是第9行郊丛,這類鉤子方法的返回類型通常是bool類型的,一般用于對某個(gè)條件進(jìn)行判斷瞧筛,如果條件滿足則執(zhí)行某一步驟厉熟,否則將不執(zhí)行。
定義具體實(shí)現(xiàn)類
本文就拿張無忌较幌、張三豐來作為例子:
public class ZhangWuJi extends AbstractSwordsman {
@Override
protected void neigong() {
System.out.println("運(yùn)行九陽神功");
}
@Override
protected void weapons() {
}
@Override
protected void moves() {
System.out.println("使用招式乾坤大挪移");
}
@Override
protected boolean hasWeapons() {
return false;
}
}
張無忌沒有武器所以hasWeapons方法返回false揍瑟,這樣也不會(huì)走weapons方法了。
public class ZhangSanFeng extends AbstractSwordsman {
@Override
protected void neigong() {
System.out.println("運(yùn)行純陽無極功");
}
@Override
protected void weapons() {
System.out.println("使用真武劍");
}
@Override
protected void moves() {
System.out.println("使用招式神門十三劍");
}
@Override
protected void hook() {
System.out.println("突然肚子不舒服乍炉,老夫先去趟廁所");
}
}
最后張三豐突然肚子不舒服所以就實(shí)現(xiàn)了鉤子方法hook绢片。
客戶端調(diào)用
public class Client {
public static void main(String[] args) {
ZhangWuJi zhangWuJi=new ZhangWuJi();
zhangWuJi.fighting();
ZhangSanFeng zhangSanFeng=new ZhangSanFeng();
zhangSanFeng.fighting();
}
}
運(yùn)行結(jié)果:
運(yùn)行九陽神功
開通正經(jīng)與奇經(jīng)
使用招式乾坤大挪移
運(yùn)行純陽無極功
開通正經(jīng)與奇經(jīng)
使用真武劍
使用招式神門十三劍
突然肚子不舒服滤馍,老夫先去趟廁所
4.模版方法模式的優(yōu)缺點(diǎn)和使用場景
優(yōu)點(diǎn)
- 模板方法模式通過把不變的行為搬移到超類,去除了子類中的重復(fù)代碼底循。
- 子類實(shí)現(xiàn)算法的某些細(xì)節(jié)巢株,有助于算法的擴(kuò)展。
缺點(diǎn)
- 每個(gè)不同的實(shí)現(xiàn)都需要定義一個(gè)子類熙涤,這會(huì)導(dǎo)致類的個(gè)數(shù)的增加阁苞,設(shè)計(jì)更加抽象。
使用場景
- 各子類中公共的行為應(yīng)被提取出來并集中到一個(gè)公共父類中以避免代碼重復(fù)祠挫。
- 面對重要復(fù)雜的算法那槽,可以把核心算法設(shè)計(jì)為模版方法,周邊相關(guān)細(xì)節(jié)功能則有各個(gè)子類實(shí)現(xiàn)茸歧。
- 需要通過子類來決定父類算法中某個(gè)步驟是否執(zhí)行倦炒,實(shí)現(xiàn)子類對父類的反向控制。