個人Java設計模式-模板方法模式

近日,ofo小黃車宣佈入駐法國巴黎,正式進入全球第20個國家,共享單車已然改變了咱們的出行方式。就拿我本身來講,每當下班出地鐵的第一件事,以光速鎖定一輛共享單車,百米衝刺的速度搶在別人以前佔領它。git

而你們都是重複着一樣的動做,拿出手機開鎖、騎車、上鎖、結算,哇~這是何等壯觀的場景,甚至還有的不用開鎖直接把車騎走的,鎖壞了嘛。github

爲何要用模板方法模式算法

如今共享單車以開鎖的方式來分,通常有掃碼開鎖和密碼開鎖兩種,來看共享單車使用流程的實現。編程

正常的思惟邏輯是,抽象一個父類,子類繼承父類並實現父類方法。OK,看抽象類代碼:設計模式

public abstract class AbstractClass {ide

// 開鎖
public abstract void unlock();
// 騎行
public abstract void ride();
// 上鎖
public abstract void lock();
// 結算
public abstract void pay();
// 用戶使用
public abstract void use();

}
抽象類定義了咱們使用共享單車的幾個基本流程,如今有兩種不一樣開鎖方式單車的使用,都繼承抽象類,代碼以下:學習

//
public class ScanBicycle extends AbstractClass {this

@Override
public void unlock() {
    System.out.println("掃碼開鎖");
}

@Override
public void ride() {
    System.out.println("騎起來很拉風");
}

@Override
public void lock() {
    System.out.println("上鎖");
}

@Override
public void pay() {
    System.out.println("結算");
}

@Override
public void use() {
    unlock();
    ride();
    lock();
    pay();
}

}
以上是經過掃碼方式開鎖騎行,再來看密碼開鎖騎行,代碼以下:設計

public class CodeBicycle extends AbstractClass {code

@Override
public void unlock() {
    System.out.println("密碼開鎖");
}

@Override
public void ride() {
    System.out.println("騎起來很拉風");
}

@Override
public void lock() {
    System.out.println("上鎖");
}

@Override
public void pay() {
    System.out.println("結算");
}

@Override
public void use() {
    unlock();
    ride();
    lock();
    pay();
}

}
好了,兩種方式都定義好了,看客戶端的調用:

public class Client {

public static void main(String[] args) {
    ScanBicycle scanBicycle = new ScanBicycle();
    scanBicycle.use();
    System.out.println("========================");
    CodeBicycle codeBicycle = new CodeBicycle();
    codeBicycle.use();
}

}
結果以下:

掃碼開鎖
騎起來很拉風
上鎖

結算

掃碼開鎖
騎起來很拉風
上鎖
結算
相信都已經看出代碼的問題,use方法的實現是同樣的,也就是代碼重複了,這是病必須得治,藥方就是模板方式模式。

模板方法模式

定義

  定義抽象類而且聲明一些抽象基本方法供子類實現不一樣邏輯,同時在抽象類中定義具體方法把抽象基本方法封裝起來,這就是模板方法模式。

UML

模板方法模式
模板方法模式涉及到的角色有兩個角色:

  • 抽象模板角色:定義一組基本方法供子類實現,定義並實現組合了基本方法的模板方法。
  • 具體模板角色:實現抽象模板角色定義的基本方法

模板方法模式還涉及到如下方法的概念:

基本方法

抽象方法:由抽象模板角色聲明,abstract修飾,具體模板角色實現。

鉤子方法:由抽象模板角色聲明並實現,具體模板角色可實現加以擴展。

具體方法:由抽象模板角色聲明並實現,而子類並不實現。

模板方法

抽象模板角色聲明並實現,負責對基本方法的調度,通常以final修飾,不容許具體模板角色重寫。模板方法通常也是一個具體方法。

模式實戰

利用模板方式模式對上面的代碼進行重構,來看抽象模板角色,代碼以下:

public abstract class AbstractClass {

protected boolean isNeedUnlock = true;  // 默認須要開鎖

/**
 * 基本方法,子類須要實現
 */
protected abstract void unlock();

/**
 * 基本方法,子類須要實現
 */
protected abstract void ride();

/**
 * 鉤子方法,子類可實現
 *
 * @param isNeedUnlock
 */
protected void isNeedUnlock(boolean isNeedUnlock) {
    this.isNeedUnlock = isNeedUnlock;
}

/**
 * 模板方法,負責調度基本方法,子類不可實現
 */
public final void use() {
    if (isNeedUnlock) {
        unlock();
    } else {
        System.out.println("========鎖壞了,不用解鎖========");
    }
    ride();
}

}
抽象模板角色定義了unlock和ride兩個使用單車的基本方法,還有一個鉤子方法,用來控制模板方法邏輯順序,核心是use模板方法,用final修飾,該方法完成對基本方法調度。注意,模板方法中對基本方法的調度是有順序有規則的。還有一點,基本方法都是protected修飾的,由於基本方法都是在以public修飾的模板方法中調用,而且能夠由子類實現,並不須要暴露給其餘類調用。

如今來看兩個具體模板角色的實現:

// 掃碼開鎖的單車
public class ScanBicycle extends AbstractClass {

@Override
protected void unlock() {
    System.out.println("========" + "掃碼開鎖" + "========");
}

@Override
protected void ride() {
    System.out.println(getClass().getSimpleName() + "騎起來很拉風");
}

protected void isNeedUnlock(boolean isNeedUnlock) {
    this.isNeedUnlock = isNeedUnlock;
}

}

// 密碼開鎖的單車
public class CodeBicycle extends AbstractClass {

@Override
protected void unlock() {
    System.out.println("========" + "密碼開鎖" + "========");
}

@Override
protected void ride() {
    System.out.println(getClass().getSimpleName() + "騎起來很拉風");
}

protected void isNeedUnlock(boolean isNeedUnlock) {
    this.isNeedUnlock = isNeedUnlock;
}

}
能夠看到,相比以前的實現,如今兩個具體類都不須要實現use方法,只負責實現基本方法的邏輯,職責上變得更加清晰了。來看用戶如何使用:

public class Client {

public static void main(String[] args) {
    ScanBicycle scanBicycle = new ScanBicycle();
    scanBicycle.use();
    
    CodeBicycle codeBicycle = new CodeBicycle();
    codeBicycle.use();
}

}
運行結果以下:

========掃碼開鎖========
ScanBicycle騎起來很拉風
========密碼開鎖========
CodeBicycle騎起來很拉風
當我以百米衝刺的速度跑到共享單車面前時,發現這輛車的鎖是壞掉的,也就是不用開鎖,免費的,騎回家收藏也沒問題。在代碼中只要調用鉤子方法isNeedUnlock就好,實現以下:

public class Client {

public static void main(String[] args) {
    ScanBicycle scanBicycle = new ScanBicycle();
    scanBicycle.isNeedUnlock(false);
    scanBicycle.use();

    CodeBicycle codeBicycle = new CodeBicycle();
    codeBicycle.isNeedUnlock(true);
    codeBicycle.use();
}

}
運行結果以下:

========鎖壞了,不用解鎖========
ScanBicycle騎起來很拉風
========密碼開鎖========
CodeBicycle騎起來很拉風
上面提到模板方法對基本方法的調度是有順序的,也就是說模板方法中的邏輯是不可變的,子類只實現能夠被實現的基本方法,但不會改變模板方法中的頂級邏輯。而鉤子方法的使用只是對模板方法中邏輯的控制,影響的是模板方法的結果,並不會改變原有邏輯。

模板方法模式的優缺點

優勢

1)良好的封裝性。把公有的不變的方法封裝在父類,而子類負責實現具體邏輯。

2)良好的擴展性:增長功能由子類實現基本方法擴展,符合單一職責原則和開閉原則。

3)複用代碼。

缺點

1)因爲是經過繼承實現代碼複用來改變算法,靈活度會下降。

2)子類的執行影響父類的結果,增長代碼閱讀難度。

總結

模板方法模式看上去簡單,可是整個模式涉及到的都是面向對象設計的核心,好比繼承封裝,基於繼承的代碼複用,方法的實現等等。當中還有涉及到一些關鍵詞的使用,也是咱們Java編程中須要掌握的基礎。整體來講,模板方法模式是很好的學習對象。下一篇是中介者模式,您的點贊和關注是個人動力,再會!

更多精彩乾貨關注「AndroidJet的開發之路」公衆號

設計模式Java源碼GitHub下載:https://github.com/jetLee92/D...

相關文章
相關標籤/搜索