設計模式之禪——模板方法模式&鉤子方法
阿新 • • 發佈:2019-01-29
**
模
**板方法模式的定義:
定義一個操作的演算法的框架,而將一些步驟延遲到子類中。使得子類可以不改變一個演算法的框架即可重定義該演算法的某些特定步驟。
例子:做一個簡單的悍馬車的模型
見UML圖
一個抽象悍馬模型類 HummerModel,然後有兩個悍馬具體型號的實現
類。見程式碼
public abstract class HummerModel {
//發動了
protected abstract void start();
//停下了
protected abstract void stop();
//喇叭發出聲音了
protected abstract void alarm();
//引擎也開始響了
protected abstract void engineBoom();
public final void run(){
this.start();
this.engineBoom();
this.alarm();
this.stop();
}
}
public class HummerH1Model extends HummerModel {
@Override
protected void start() {
System.out.println("悍馬H1發動" );
}
@Override
protected void stop() {
System.out.println("悍馬H1停車");
}
@Override
protected void alarm() {
System.out.println("悍馬H1鳴笛");
}
@Override
protected void engineBoom() {
System.out.println("悍馬H1引擎發出聲響");
}
}
public class HummerH2Model extends HummerModel{
@Override
protected void start() {
System.out.println("悍馬H2發動");
}
@Override
protected void stop() {
System.out.println("悍馬H2停車");
}
@Override
protected void alarm() {
System.out.println("悍馬H2鳴笛");
}
@Override
protected void engineBoom() {
System.out.println("悍馬H2引擎發出聲響");
}
}
ok,模板方法模式體現在哪裡呢?注意它的定義:定義一個操作的演算法的框架。很明顯,抽象類中的run方法就是這個演算法的框架,也就是模板。
模板方法模式就是如此簡單~ 我們來看一下它的通用模板
public abstract class AbstractClass{
//基本方法
protected abstract void doSomething();
//基本方法
protected abstract void doAnything();
//模板方法
public final void tempeteMethod(){
this.doSomething();
this.doAnything();
}
}
public class ConcreteClass1 extends AbstractClass{
protected void doAnything(){
//邏輯處理
}
protected void doSomething(){
//邏輯處理
}
}
public class ConcreteClass2 extends AbstractClass{
protected void doAnything(){
//邏輯處理
}
protected void doSomething(){
//邏輯處理
}
}
模板方法模式的優點
- 封裝不變的內容,擴充套件可變部分,如果我們要新增一個H3悍馬模型,只需要繼承父類就可以了。
- 提取公共部分程式碼,便於維護
- 行為由父類控制,子類實現。基本方法是由子類實現的,因此子類可以通過拓展的方法增加相應的功能,符合開閉原則。
模板方法模式的使用場景
- 多個子類有公有的方法,並且邏輯基本相同時
- 重複、複雜的演算法,可以把核心演算法設計為模板方法,周邊的細節則有各個子類實現
程式碼重構時,模板方法模式是一個經常使用的模式,把相同的程式碼抽取到父類中,然後用鉤子方法(見下面的”模板方法拓展“)約束其行為。
模板方法模式的拓展(鉤子方法)
上面的程式碼有個問題,喇叭是預設響的,人不能控制,怎麼完善呢?
注意!鉤子方法應該是最開始設計就有的,而不是去完善、糾正錯誤的
public abstract class HummerModel {
//是否能發動
protected boolean isAlarm() {
return false;
}
//發動了
protected abstract void start();
//停下了
protected abstract void stop();
//喇叭發出聲音了
protected abstract void alarm();
//引擎也開始響了
protected abstract void engineBoom();
public final void run(){
this.start();
this.engineBoom();
if(this.isAlarm()){
this.alarm();
}
this.stop();
}
}
public class HummerH1Model extends HummerModel {
private boolean alarmFlag = true;
public void setAlarm(boolean isAlarm){
alarmFlag = isAlarm;
}
@Override
protected boolean isAlarm(){
return this.alarmFlag;
}
@Override
protected void start() {
System.out.println("悍馬H1發動");
}
@Override
protected void stop() {
System.out.println("悍馬H1停車");
}
@Override
protected void alarm() {
System.out.println("悍馬H1鳴笛");
}
@Override
protected void engineBoom() {
System.out.println("悍馬H1引擎發出聲響");
}
}
雖然這裡有模板方法,但是通過鉤子方法我們還是能夠影響到模板方法的執行(不是影響它的邏輯)。鉤子方法在我們平時的程式設計過程中也是非常常見的。