1. 程式人生 > >【設計模式】之模板方法(Template Method)

【設計模式】之模板方法(Template Method)

模板方法的定義為:再一個操作中定義一個演算法的骨架,將演算法中的一些步驟延遲到子類去實現。模板方法允許子類在不該變演算法結構的情況下重新定義演算法的某些步驟。

Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.

在實際的面向物件設計中,模板方法的使用應該是非常廣泛的。

模板方法一個很重要的作用,就是提高程式碼複用性,避免程式碼冗餘。如果出現重複程式碼,就應該考慮是不是設計出錯了。(When we got code duplication, that's a good sign we need to clean up the design)。

模板方法,顧名思義就是一個方法(method),在這個方法內部定義了一個演算法的模板,演算法的結構是不會變化的,演算法中不變的部分會在模板方法所在的類中封裝,依賴於具體實現的部分則在其他地方定義。

模板方法符合Holleywood Principle,即 "Don't call us, we'll call you“。

public abstract class CaffeineBeverageWithHook {
    final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        if (customerWantsCondiments()) {
            addCondiments();
        }
    }

    abstract void brew();

    abstract void addCondiments();

    void boilWater() {
        System.out.println("Boiling water");
    }

    void pourInCup() {
        System.out.println("Pouring into cup");
    }

    boolean customerWantsCondiments() {
        return true;
    }
}
CaffeineBeverageWithHook定義是一個抽象類,prepareRecipe方法就是一個模板方法,為了不讓子類改變方法的結構,用關鍵字final修飾後,子類便無法override模板方法。

prepareRecipe內部定義一個演算法,演算法中呼叫了兩個抽象方法brew和boilWater,所以這個演算法是抽象的,它必須依賴與具體的實現才能執行。

在模板方法中還有一個比較重要的概念就是Hook,所謂Hook的定義如下:

hook operations, which provide default behavior that subclass can extend if necessary. A hook operation often does nothing by default. -- <Design Patterns>

A hook is a method that is declared in the abstract class, but only given an empty and default implementation. -- <Head First Design Patterns>

類CaffeineBeverageWithHook中的customerWantsCondiments就是一個hook操作。

customerWantsCondiments的具體實現定義在CaffeineBeverageWithHook的子類中。

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class CoffeeWithHook extends CaffeineBeverageWithHook {
    public void brew() {
        System.out.println("Dripping Coffee though filter");
    }

    public void addCondiments() {
        System.out.println("Adding Sugar and Milk");
    }

    public boolean customerWantsCondiments() {
        String answer = getUserInput();
        return answer.toLowerCase().startsWith("y");
    }
    
    private String getUserInput() {
        String answer = null;
        System.out.println("Would you like milk and sugar with your coffee (y/n)?");
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        try {
            answer = in.readLine();
        } catch (IOException ioe) {
            System.err.println("IO error trying to read your answer");
        }
        if (answer == null) {
            return "no";
        }
        return answer;
    }
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class TeaWithHook extends CaffeineBeverageWithHook {
    public void brew() {
        System.out.println("Steeping the tea");
    }

    public void addCondiments() {
        System.out.println("Adding Lemon");
    }

    public boolean customerWantsCondiments() {
        String answer = getUserInput();
        return answer.toLowerCase().startsWith("y");
    }
    
    private String getUserInput() {
        String answer = null;
        System.out.println("Would you like lemon with your tea (y/n)?");
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        try {
            answer = in.readLine();
        } catch (IOException ioe) {
            System.err.println("IO error trying to read your answer");
        }
        if (answer == null) {
            return "no";
        }
        return answer;
    }
}

編寫測試驅動
public class BeverageTestDrive {
    public static void main(String[] args) {
        TeaWithHook teaHook = new TeaWithHook();
        CoffeeWithHook coffeeHook = new CoffeeWithHook();

        System.out.println("\nMaking tea...");
        teaHook.prepareRecipe();
        
        System.out.println("\nMaking coffee...");
        coffeeHook.prepareRecipe();
    }
}

執行結果如下:



當然,模板方法的實現並非都是通過的繼承的方式實現。

以下例子便是再模板方法中呼叫了其他類的方法。

import java.util.Arrays;
public class DuckSortTestDrive {
    public static void main(String[] args) {
        Duck[] ducks = {
            new Duck("Daffy", 8),
            new Duck("Dewey", 2),
            new Duck("Howard", 7),
            new Duck("Louie", 2),
            new Duck("Donald", 10),
            new Duck("Huey", 2)
        };

        System.out.println("Before sorting");
        display(ducks);

        Arrays.sort(ducks);

        System.out.println("\nAfter sorting");
        display(ducks);
    }

    public static void display(Duck[] ducks) {
        for (Duck duck : ducks) {
            System.out.println(duck);
        }
    }
}

Arrays的靜態方法sort便是一個模板方法,它需要呼叫傳入引數物件的comareTo方法。
public class Duck implements Comparable {
    String name;
    int weight;

    public Duck(String name, int weight) {
        this.name = name;
        this.weight = weight;
    }

    public String toString() {
        return name + " weights " + weight;
    }

    @Override
    public int compareTo(Object object) {
        Duck otherDuck = (Duck)object;

        if (this.weight < otherDuck.weight) {
            return -1;
        } else if (this.weight == otherDuck.weight) {
            return 0;
        } else { // this.weight > otherDuck.weight
            return 1;
        }
    }
}

模板方法模式與策略模式有相似點,他們都封裝了一個演算法,但是模板放發只是抽象了演算法的一部分,而策略模式抽象的是整個演算法,而且策略模式是同哦那天過組合(Composition)實現,模板方法模式,主要是利用了inheritance。

書中有寫:The template method calls primitive operations as well as operations defined in AbstractClass or those of others.

相關推薦

設計模式模板方法Template Method

模板方法的定義為:再一個操作中定義一個演算法的骨架,將演算法中的一些步驟延遲到子類去實現。模板方法允許子類在不該變演算法結構的情況下重新定義演算法的某些步驟。 Define the skeleton of an algorithm in an operation, defe

java設計模式 模板方法Template Method模式

1. 模板方法的一個例項         這一節主要來學習一下設計模式中的模板方法模式。我們先來看一個例子:假如現在老闆讓你做一個汽車的模型,要求只要完成基本功能即可,不考慮擴充套件性,那你會怎麼做呢?我們首先會根據經驗設計一個類圖:        由這個類圖可知,非

設計模式模板方法模式

1.模式動機與定義 模板方法定義:定義一個操作中演算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個演算法的結構即可重定義該演算法的特定步驟。 模板方法是一種行為型模式。 2.模式結構與分析 /** * 實現了一個模板方法,定義了演算法的骨架。 * 具體子類將重新定義primi

為什麼學習模板方法Template Method模式模板方法Template Method模式主要解決的問題

轉載 https://blog.csdn.net/eson_15/article/details/51323902 1. 模板方法的一個例項         這一節主要來學習一下設計模式中的模板方法模式。我們先來看一個例子:假如現在老闆讓你做一個汽車的模型,要求只要完成基

設計模式的征途—17.模板方法Template Method模式

opened res ati 相同 rom 配置 version factor creat 在現實生活中,很多事情都需要經過幾個步驟才能完成,例如請客吃飯,無論吃什麽,一般都包含:點單、吃東西、買單等幾個步驟,通常情況下這幾個步驟的次序是:點單=>吃東西=>買單

C++設計模式——模板方法Template Method

模板方法(template method)設計模式用於定義一個包含許多步驟的演算法框架,允許子類重寫(覆蓋)演算法的某一個步驟而不改變演算法整體的流程和框架。 模板方法提供的流程是骨架,子類無須覆蓋模板方法本身,只需繼承即可,即模板方法無須是 virtu

java設計模式 單例Singleton模式

1. 單例模式的定義         單例模式(Singleton Pattern)是一個比較簡單的模式,其原始定義如下:Ensure a class has only one instance, and provide a global point of access

java設計模式 責任鏈chain of resposibility模式

  責任鏈模式,顧名思義,就是一條鏈。這個鏈到底是怎麼執行的呢?它主要是將能夠處理同一類請求的物件連成一條鏈,所提交的請求沿著鏈傳遞,鏈上的物件逐個判斷是否有能力處理該請求,如果能則處理,如果不能則

java設計模式 建造者Builder模式

        我們還是舉上一節的例子:生產汽車。上一節我們通過模板方法模式控制汽車跑起來的動作,那麼需求是無止境的,現在如果老闆又增加了額外的需求:汽車啟動、停止、鳴笛引擎聲都由客戶自己控制,他想要什麼順序就什麼順序,那該如何做呢? 1. 汽車無休止的改造       

設計模式物件池模式--JDBC連線池簡單實現案例

文章目錄 物件池設計模式 物件池設計模式的目標 問題 討論 結構 示例 核驗單 經驗法則 連線池模式示例程式碼 ObjectPool.java

設計模式代理模式

1.模式動機與定義 代理模式定義:為其他物件提供一種代理以控制物件的訪問。 2.模式結構與分析 proxy.png /** * 定義了RealSubject和Proxy的共同介面,使得在任何使用RealSubject的地方都可以使用Proxy */ public interface Subject

設計模式觀察者模式

觀察者模式 什麼是觀察者模式 觀察者模式屬於行為模式的一種,定義了物件的通用交流方式。 觀察者模式定義了一對多的關係,一個物件改變了狀態,則其它所有依賴它的物件都會收到通知。 觀察者模式有時候在網路模

設計模式工廠方法Factory Method

一 目的    定義一個建立物件的介面,但是讓他的子類去決定初始化哪種型別。工廠方法使得一個類能夠推遲到他的子類去初始化。二 動機    框架運用抽象類來定義和維護物件之間的關係。一個框架經常負責這些物件的建立。考慮一些這麼一個情況:一個能夠展現多個文件的應用程式的框架。在這

設計模式六大原則之一單一職責與開閉原則

【前言】         最近在學習設計模式,設計模式是面向物件程式設計的。設計模式有6大原則,而實際上都是互補的,也就是說一些原則需要利用另一些原則來實現自己。下面來簡單的介紹一下六大原則其中之二 【單一職責原則】 1、單一職責原則的由來         初學者在程式設計

.NET設計模式-模版方法Template Method

摘要:Template Method模式是比較簡單的設計模式之一,但它卻是程式碼複用的一項基本的技術,在類庫中尤其重要。主要內容1.概述2.Template Method解說3..NET中的Template Method模式4.適用性及實現要點概述變化一直以來都是軟體設計的永恆話題,在XP程式設計中提倡擁抱變

模版方法Template Method

“元件協作”模式: 現代軟體專業分工之後的第一個結果是“框架與應用程式的劃分”,“元件協作”模式通過晚期繫結,來實現框架與應用程式之間的鬆耦合,使二者之間協作時常用的模式。 典型模式 Template Method Strategy Observer / Eve

Java23種設計模式19----》模板方法模式template method

一、場景 流程骨架清楚,但具體實現還不清楚 如吃飯,吃飯流程都知道,但具體吃什麼飯不清楚 二、模板方法模式介紹 定義好骨架,但具體某個方法該怎麼調不知道 三、核心 四、方法回撥(鉤子方法) 五、什麼時候用模板方法模式 六、開發中的場景 七

GOF23設計模式模板方法模式template method

評分 end 抽象方法 abs 方法調用 轉移 pri spa 應用 一、模板方法模式概述   模板方法模式是編程中經常使用的模式。它定義了一種操作中的算法架構,將某些步驟延遲到子類中實現。這樣,新的子類可以在不改變一個算法結構的前提下重新定義該算法的某些特定步驟。   (

設計模式模板方法模式

模式定義 模板方法模式在一個方法中定義一個演算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變演算法結構的情況下,重新定義演算法中的某些步驟。 下圖是該模式的類圖: 一個生動的例子 模板類: public abstract class CaffeineBe