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

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

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

爲何要用模板方法模式

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

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

public abstract class AbstractClass {
    // 開鎖
    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 {
    @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();
    }
}
複製代碼

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

public class CodeBicycle extends AbstractClass {
    @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();
    }
}
複製代碼

結果以下:this

掃碼開鎖spa

騎起來很拉風設計

上鎖

結算

========================

掃碼開鎖

騎起來很拉風

上鎖

結算

相信都已經看出代碼的問題,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編程中須要掌握的基礎。整體來講,模板方法模式是很好的學習對象。下一篇是中介者模式,您的點贊和關注是個人動力,再會!

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

AndroidJet的開發之路
相關文章
相關標籤/搜索