日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 设计模式之模板方法模式

發布時間:2024/9/30 java 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 设计模式之模板方法模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、了解模板方法模式

1.1 什么是模板方法模式

模板方法模式 Template Method Parrern)在一個方法中定義了一個算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以在不改變算法結構的情況下,重新定義方法中的某些步驟。

模板就是一個方法,更具體的說,這個方法將算法定義為一組步驟,其中的任何步驟都可以是抽象的,由子類負責實現。這可以確保算法的結構保持不變,同時由子類提供部分實現。

1.2 模板方法模式組成結構

  • 抽象類(AbstractClass):包含模板方法,定義了算法的骨架。專注于算法本身。
  • 具體類(ConcreteClass):實現抽象類中的抽象方法,完成算法的實現。

1.3 模板方法 UML 圖解

1.4 模板方法的適用場景

  • 在某些類的算法中,用了相同的方法,造成代碼的重復。
  • 控制子類擴展,子類必須遵守算法規則。

二、模板方法模式具體應用

2.1 問題描述

茶與咖啡:有的人喜歡喝茶,而有的人 喜歡喝咖啡。茶與咖啡 之間有什么共同的成分嗎?答案是咖啡因 (怎么樣,沒想到吧)。不止是這樣,茶與咖啡的沖泡方式也十分類似。如下

茶沖泡法:

  • 把水煮沸
  • 用沸水沖泡咖啡
  • 把咖啡倒進杯子
  • 加糖和牛奶
  • 咖啡沖泡法:

  • 把水煮沸
  • 用沸水浸泡茶葉
  • 把茶倒進杯子
  • 加檸檬
  • 現在我們來設計代碼,完成茶與咖啡的沖泡。

    2.2 簡單設計實現

    因為代碼比較簡單,所以這里只提供代碼實現的設計圖。從上面的設計圖中,我們應該能發現一個問題:存在著一些重復的代碼 (boilWater() 與 pourInCup())。所以我們要重新考慮一下設計,來避免這個問題。

    PS:有一個重要的設計原則:找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的代碼混在一起。

    于是我們可能想到使用繼承,把不變的代碼方法超類中,把變化的代碼放在子類中去實現。

    2.3 使用繼承

    這種通過繼承的設計感覺還不錯,可以很好的解決問題。但是我們仔細想想,沖泡茶與咖啡是不是還存在一些共同點呢?其實 brewCoffeeGrinds() 與 steepTeaBag() 的動作很類似,因此我們可以使用 brew() 來統一這兩個方法;addSugarAndMilk() 與 addLemon() 也很類似,我們用 addCondiments() 來統一。

    2.4 模板方法模式登場

    (1) 模板方法 UML 設計 (可參考模板方法 UML 圖解)

    (2) 模板方法代碼實現

    抽象 CaffineBeverage 類

    package com.jas.templatemethod;public abstract class CaffineBeverage {/*** 模板方法,用作一個算法的模板,用于制作茶與咖啡* 并定義為 final 的,防止子類覆蓋*/final void prepareRecipe(){boilWater();brew();pourInCup();addCondiments();}void boilWater(){System.out.println("煮沸水!");}abstract void brew();void pourInCup(){System.out.println("倒進杯子里!");}abstract void addCondiments(); }

    具體 Tea 類

    package com.jas.templatemethod;public class Tea extends CaffineBeverage {@Overridevoid brew() {System.out.println("用沸水浸泡茶葉!");}@Overridevoid addCondiments() {System.out.println("加入檸檬!");} }

    具體 Coffee 類

    package com.jas.templatemethod;public class Coffee extends CaffineBeverage {@Overridevoid brew() {System.out.println("用沸水浸泡咖啡!");}@Overridevoid addCondiments() {System.out.println("加入糖與牛奶!");} }

    測試類

    package com.jas.templatemethod;public class Test {public static void main(String[] args) {CaffineBeverage coffee = new Coffee();CaffineBeverage tea = new Tea();coffee.prepareRecipe();System.out.println();tea.prepareRecipe();} }/*** 輸出* 煮沸水!* 用沸水浸泡咖啡!* 倒進杯子里!* 加入糖與牛奶!** 煮沸水!* 用沸水浸泡茶葉!* 倒進杯子里!* 加入檸檬!*/

    (3) 問題總結

    CaffineBeverage 類主導一切,它擁有算法,并保護這個算法 (模板方法定義為 final 的)。對于子類來說,因為 CaffineBeverage 類的存在,代碼能夠最大程度的復用。并且算法存在于模板方法中,更易于修改,并且擴展性更強。CaffineBeverage 類本身專注與算法本身,由子類提供完整實現。

    2.5 對模板方法進行掛鉤

    (1) 什么是鉤子

    鉤子 (Hook) 是一種被聲明抽象類中的方法,但是只有空的或默認的實現。
    鉤子的存在,可以讓子類有能力對算法的不同點進行掛鉤。到底要不要掛鉤,由子類自行決定。

    (2) 將鉤子應用到代碼中去

    改造 CaffineBeverage

    package com.jas.templatemethod;public abstract class CaffineBeverageWithHook {final void prepareRecipe(){boilWater();brew();pourInCup();/** 這里加上鉤子的判斷,只有鉤子返回值為 true 時,表示顧客想要加調料,才添加調料*/if(customerWantsCondiments()){addCondiments();}else {System.out.println("不添加任何調料");}}void boilWater(){System.out.println("煮沸水!");}abstract void brew();void pourInCup(){System.out.println("倒進杯子里!");}abstract void addCondiments();/*** 這是一個鉤子,子類可以自行選擇覆蓋,但是也可以不這么做。* @return*/boolean customerWantsCondiments(){return true;} }

    改造 Coffee

    package com.jas.templatemethod;import java.util.Scanner;public class CoffeeWithHook extends CaffineBeverageWithHook {@Overridevoid brew() {System.out.println("用沸水浸泡咖啡!");}@Overridevoid addCondiments() {System.out.println("加入糖與牛奶!");}@Overrideboolean customerWantsCondiments() {/** 只有當用戶輸入的是 'y' 時,返回 true,才添加調料 */if("y".equals(getUserInput())){return true;}else {return false;}}/*** 獲得用戶在控制臺輸入的數據* @return*/private String getUserInput(){String answer = null;System.out.println("你是否想要添加調料,請輸入 (y/n)");Scanner read = new Scanner(System.in);answer = read.nextLine();return answer;} }

    測試

    package com.jas.templatemethod;public class Test {public static void main(String[] args) {CaffineBeverageWithHook coffeeWithHook = new CoffeeWithHook();coffeeWithHook.prepareRecipe();}/*** 輸出* 煮沸水!* 用沸水浸泡咖啡!* 倒進杯子里!* 你是否想要添加調料,請輸入 (y/n)* y* 加入糖與牛奶!*/ }

    (3) 鉤子總結

    在實際工作中,如果算法的這個部分是可選的,那么你可以選擇使用鉤子。
    鉤子可以讓子類實現算法中可選的部分,或者在鉤子對子類的實現并不重要時,子類可以對此鉤子置之不理。
    鉤子可以使子類能夠有機會對模板方法中即將發生的步驟做出反應。

    三、 模板方法模式總結

    3.1 模板方法優缺點總結

    優點

    • 封裝不變部分,擴展可變部分。
    • 提取公共代碼,便于維護。
    • 行為由父類控制,子類實現。

    缺點

    每一個不同的實現都需要一個子類來實現,導致類的個數增加,使得系統更加龐大。

    3.2 模板方法模式知識點總結

    • 模板方法”定義了算法的實現步驟,并把一些步驟的實現推遲到子類中。
    • 模板方法模式為我們提供了一種代碼復用的技巧。
    • 模板方法的抽象類可以定義具體方法、抽象方法和鉤子。抽象方法由其子類實現。
    • 鉤子是一種方法,它在抽象類中不做事,或者只做一些默認的事,子類可以選擇要不要覆蓋它。
    • 為了防止子類覆蓋模板方法,可以將模板方法定義為 final 的。
    • 可以把工廠方法理解為模板方法的一種特殊版本。

    PS:點擊了解更多設計模式 http://blog.csdn.net/codejas/article/details/79236013

    參考文獻

    《Head First 設計模式》

    總結

    以上是生活随笔為你收集整理的Java 设计模式之模板方法模式的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。