13.java設計模式之模板模式

xiaokantianse發表於2020-11-25

基本需求:

  • 製作豆漿的流程 選材--->新增配料--->浸泡--->放到豆漿機打碎
  • 通過新增不同的配料,可以製作出不同口味的豆漿
  • 選材、浸泡和放到豆漿機打碎這幾個步驟對於製作每種口味的豆漿都是一樣的
  • 通過模板方法可以完成

基本介紹:

  • 模板方法模式(Template Method),又叫模板模式(Template),在一個抽象類公開定義了執行它的方法的模板。它的子類可以按需要重寫方法實現,但呼叫將以抽象類中定義的方式進行

  • 模板方法模式 定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中,使得子類可以不改變一個演算法的結構,就可以重定義該演算法的某些特定步驟,這種型別的設計模式屬於行為型模式

  • UML類圖(原理)

    • 說明

      • AbstractClass:抽象類,其中的template()為模板方法

        • public final void template() {
             // 在模板方法內部呼叫其他方法 規定演算法的具體流程,這些方法可以是抽象的,也可以不是抽象的
             // 抽象的方法就交由子類實現,子類不改變演算法的結構重定義演算法的某些步驟
             // 模板方法內部呼叫自身實現的方法,可作為鉤子方法,讓子類有選擇的去實現
             operation1();
             operation2();
          }
          
      • ConcreationClass:實現類,對template()方法內部所使用的方法進行實現,對鉤子方法可以選擇性的實現,不實現則使用父類的實現

  • UML類圖(案例)

  • 程式碼實現

    • public abstract class SoyMilk {
      
         // 模板方法 使用final 不能讓子類重寫,定義好具體的演算法流程,其實現子類去實現
         public final void make() {
             select();
             if (isAdd()) {
                 // 使用鉤子方法判斷是否需要加配料 預設加
                 add();
             }
             soak();
             beat();
         }
      
         // 新增配料方法 ,不同品種的豆漿,加的配料不一樣
         public abstract void add();
      
         // 該方法為鉤子方法,子類可根據情況是否實現該方法
         public boolean isAdd() {
             return true;
         }
      
         public void select() {
             System.out.println("選擇好的新鮮黃豆");
         }
      
         public void soak() {
             System.out.println("黃豆和配料開始浸泡,需要3小時");
         }
      
         public void beat() {
             System.out.println("黃豆和配料放到豆漿機去打碎");
         }
      
      }
      
      // 子類一
      class RedBeanSoyMilk extends SoyMilk {
         // 重寫新增方法
         @Override
         public void add() {
             System.out.println("新增上好的紅豆");
         }
      
      }
      
      // 子類二
      class PeanutSoyMilk extends SoyMilk {
         // 重寫新增方法
         @Override
         public void add() {
             System.out.println("新增上好的花生");
         }
      
      }
      
      // 子類三
      class PureSoyMilk extends SoyMilk {
         // 重寫新增方法 和 鉤子方法
         @Override
         public void add() {
             System.out.println("新增上好的花生");
         }
      
         @Override
         public boolean isAdd() {
             return false;
         }
      }
      
    • public class Client {
         public static void main(String[] args) {
             // 製作紅豆豆漿 呼叫模板方法
             SoyMilk redBeanSoyMilk = new RedBeanSoyMilk();
             redBeanSoyMilk.make();
             // 製作花生豆漿 呼叫模板方法
             SoyMilk peanutSoyMilk = new PeanutSoyMilk();
             peanutSoyMilk.make();
             // 製作純豆漿 重寫了鉤子方法 呼叫模板方法
             SoyMilk pureSoyMilk = new PureSoyMilk();
             pureSoyMilk.make();
         }
      }
      

spring原始碼:

  • 在spring的IOC容器中就使用到了模板模式
  • UML類圖
    • 說明
      • refresh()方法呼叫該類很多方法,也就是模板方法
      • obtainFreshBeanFactory()方法內部呼叫了refreshBeanFactory()和getBeanFactory()方法,這兩個方法是抽象方法,交由了子類去完成
      • postProcessBeanFactory()和onRefresh()方法為鉤子方法,在AbstractApplicationContext()內部進行了空實現,子類可以有選擇的進行重寫

注意事項:

  • 基本思想是:演算法只存在於一個地方,也就是在父類中,容易修改。需要修改演算法時,只要修改父類的模板方法或者已經實現的某些步驟,子類就會繼承這些修改
  • 實現了最大化程式碼複用。父類的模板方法和已實現的某些步驟會被子類繼承而直接使用
  • 既統一了演算法,也提供了很大的靈活性。父類的模板方法確保了演算法的結構保持不變,同時由子類提供部分步驟的實現
  • 該模式的不足之處:每一個不同的實現都需要一個子類實現,導致類的個數增加,使得系統更加龐大
  • 一般模板方法都加上 final 關鍵字, 防止子類重寫模板方法
  • 模板方法模式使用場景:當要完成在某個過程,該過程要執行一系列步驟 ,這一系列的步驟基本相同,但其個別步驟在實現時可能不同,通常考慮用模板方法模式來處理

相關文章