**
**板方法模式的定義:
定義一個操作的算法的框架,而將一些步驟延遲到子類中。使得子類可以不改變一個算法的框架即可重定義該算法的某些特定步驟。
例子:做一個簡單的悍馬車的模型
見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引擎發出聲響");
}
}
雖然這里有模板方法,但是通過鈎子方法我們還是能夠影響到模板方法的執行(不是影響它的邏輯)。鈎子方法在我們平時的編程過程中也是非常常見的。
鈎子函數總結
鈎子方法源於設計模式中模板方法模式,模板方法模式中分為兩大類:模版方法和基本方法,而基本方法又分為:抽象方法,具體方法,鈎子方法。
當然這里不細說模板方法模式,對於鈎子方法,是對於抽象方法或者接口中定義的方法的一個空實現,在實際中的應用,比如說有一個接口,這個接口里有7個方法,而你只想用其中一個方法,那么這時,你可以寫一個抽象類實現這個接口,在這個抽象類里將你要用的那個方法設置為abstract,其它方法進行空實現,然后你再繼承這個抽象類,就不需要實現其它不用的方法,這就是鈎子方法的作用。