最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java設(shè)計(jì)模式之模板方法模式Template Method Pattern詳解

 更新時(shí)間:2022年11月01日 14:56:19   作者:流煙默  
在我們實(shí)際開(kāi)發(fā)中,如果一個(gè)方法極其復(fù)雜時(shí),如果我們將所有的邏輯寫(xiě)在一個(gè)方法中,那維護(hù)起來(lái)就很困難,要替換某些步驟時(shí)都要重新寫(xiě),這樣代碼的擴(kuò)展性就很差,當(dāng)遇到這種情況就要考慮今天的主角——模板方法模式

概述

模板方法

模板方法定義了一個(gè)算法的步驟,并允許子類(lèi)為一個(gè)或多個(gè)步驟提供實(shí)現(xiàn)。那么什么是模板方法呢?我們看下模板方法的定義。

  1. 一個(gè)具體方法而非抽象方法,其用作一個(gè)算法的模板;
  2. 在模板方法中,算法內(nèi)的大多數(shù)步驟都被某個(gè)方法代表;
  3. 模板方法中某些方法是子類(lèi)處理
  4. 需要由子類(lèi)提供的方法,必須在超類(lèi)中聲明為抽象方法;
  5. 模板方法通常不能被覆蓋,也就是使用final修飾;

模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),指在一個(gè)抽象類(lèi)公開(kāi)定義了執(zhí)行它的方法的模板。它的子類(lèi)可以按需要重寫(xiě)方法實(shí)現(xiàn),但調(diào)用將以抽象類(lèi)中定義的方式進(jìn)行簡(jiǎn)單說(shuō),模板方法模式定義一個(gè)操作中的算法的骨架,而將一些步驟延遲到子類(lèi)中,使得子類(lèi)可以不改變一個(gè)算法的結(jié)構(gòu),就可以重定義該算法的某些特定步驟。

這種類(lèi)型的設(shè)計(jì)模式屬于行為型模式。

如下實(shí)例,prepareRecipe就是一個(gè)模板方法。

public abstract class CaffeineBeverage {
   final void  prepareRecipe(){
       boilWater();
       brew();
       pourInCup();
       addCondiments();
   }
   protected abstract void addCondiments();
   protected abstract void pourInCup();
   protected abstract void brew();
   protected abstract void boilWater();
}

模板方法模式

在一個(gè)方法中定義一個(gè)算法的骨架,而將一些步驟延遲到子類(lèi)中。模板方法使得子類(lèi)可以在不改變算法結(jié)構(gòu)的情況下,重新定義算法中的某些步驟。

這個(gè)模式是用來(lái)創(chuàng)建一個(gè)算法的模板。什么是模板?如你所見(jiàn)的,模板就是一個(gè)方法。更具體地說(shuō),這個(gè)方法將算法定義成一組步驟,其中的任何步驟都可以是抽象的,由子類(lèi)負(fù)責(zé)實(shí)現(xiàn)。這可以確保算法的結(jié)構(gòu)保持不變,同時(shí)由子類(lèi)提供部分實(shí)現(xiàn)。

對(duì)上面實(shí)例進(jìn)一步擴(kuò)展,我們看下抽象類(lèi)內(nèi)可以有哪些類(lèi)型的方法。

public abstract class CaffeineBeverage {
   final void  prepareRecipe(){
       boilWater();
       brew();
       pourInCup();
       addCondiments();
       concreteOperation();
       hook();
   }
   protected abstract void addCondiments();
   protected abstract void pourInCup();
   protected abstract void brew();
   protected abstract void boilWater();
      final void concreteOperation(){
	// 這里是實(shí)現(xiàn)
   }
	//空方法
   void hook(){};
}

可以看到有一個(gè)具體的concreteOperation方法,final表示其不可以被子類(lèi)覆蓋。我們也可以由“默認(rèn)不做事的方法”,我們稱這種方法為“hook”(鉤子)。子類(lèi)可以視情況決定要不要覆蓋他們。

鉤子是一種被聲明在 抽象類(lèi)中的方法,但只有空的或者默認(rèn)的實(shí)現(xiàn)。鉤子的存在,可以讓子類(lèi)有能力對(duì)算法的不同點(diǎn)進(jìn)行掛鉤。要不要掛鉤,由子類(lèi)決定。每一個(gè)具體的子類(lèi)都必須定義所有的抽象方法,并為模板方法算法中未定義步驟提供完整的實(shí)現(xiàn)。

那么什么時(shí)候使用抽象方法什么時(shí)候使用鉤子呢?

答,當(dāng)你的子類(lèi)必須提供算法中某個(gè)算法或步驟的實(shí)現(xiàn)時(shí),就是用抽象方法。如果算法的這個(gè)部分是可選的,就用鉤子。如果是鉤子的話,子類(lèi)可以選擇實(shí)現(xiàn)這個(gè)鉤子,但并不強(qiáng)制這么做。

使用鉤子的真正目的是什么?

鉤子有幾種用法。如我們之前所說(shuō)的,鉤子可以讓子類(lèi)實(shí)現(xiàn)算法中可選的部分,或者在鉤子對(duì)于子類(lèi)的實(shí)現(xiàn)并不重要的時(shí)候,子類(lèi)可以對(duì)此鉤子置之不理。鉤子的另一個(gè)用法,是讓子類(lèi)能夠有機(jī)會(huì)對(duì)模板方法中某些即將發(fā)生的(或剛剛發(fā)生的)步驟作出反應(yīng)。比方說(shuō),名為justReOrderedList()的鉤子方法允許子類(lèi)在內(nèi)部列表重新組織后執(zhí)行某些動(dòng)作(例如在屏幕上重新顯示數(shù)據(jù))。正如前面提到的,鉤子也可以讓子類(lèi)有能力為其抽象類(lèi)作一些決定。

好萊塢原則

好萊塢原則簡(jiǎn)單來(lái)講就是:別調(diào)用我們,我們會(huì)調(diào)用你。

好萊塢原則可以給我們一種防止“依賴腐敗”的方法。當(dāng)高層組件依賴低層組件,而低層組件又依賴高層組件,而高層組件又依賴邊側(cè)組件,邊側(cè)組件又依賴低層組件時(shí),依賴腐敗就發(fā)生了。在這種情況下,沒(méi)有人可以輕易地搞懂系統(tǒng)是如何設(shè)計(jì)的。

在好萊塢原則之下,我們?cè)试S低層組件將自己掛鉤到系統(tǒng)上,但是高層組件會(huì)決定什么時(shí)候和怎樣使用這些低層組件。換句話說(shuō),高層組件對(duì)待低層組件的方式就是“別調(diào)用我們,我們會(huì)調(diào)用你”。

模板方法模式就契合該原則。當(dāng)我們?cè)O(shè)計(jì)模板方法模式時(shí),我們告訴子類(lèi),“不要調(diào)用我們,我們會(huì)調(diào)用你”。

那么低層組件完全不可以調(diào)用高層組件的方法嗎?并不盡然!

事實(shí)上,低層組件在結(jié)束時(shí),常常調(diào)用從超類(lèi)中繼承來(lái)的方法。我們所要做的是,避免讓高層和低層組件之間有明顯的環(huán)狀依賴。

好萊塢原則與依賴倒置原則

依賴倒置原則教我們盡量避免使用具體類(lèi),而多使用抽象類(lèi)。而好萊塢原則是用在創(chuàng)建框架或組件上的一種技巧,好讓低層組件能夠被掛鉤進(jìn)計(jì)算中,而且又不會(huì)讓高層組件依賴低層組件。兩者的目標(biāo)都是在于解耦,但是依賴倒置原則更加注重如何在設(shè)計(jì)中避免依賴。

好萊塢原則教我們一個(gè)技巧,創(chuàng)建一個(gè)有彈性的設(shè)計(jì),允許低層結(jié)構(gòu)能夠互相操作,而又防止其他類(lèi)太過(guò)依賴它們。

真實(shí)案例

數(shù)組類(lèi)Arrays的mergeSort方法就是一個(gè)模板方法。

 private static void mergeSort(Object[] src,
                                  Object[] dest,
                                  int low,
                                  int high,
                                  int off) {
        int length = high - low;
        // Insertion sort on smallest arrays
        if (length < INSERTIONSORT_THRESHOLD) {
            for (int i=low; i<high; i++)
                for (int j=i; j>low &&
                         ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
                    swap(dest, j, j-1);
            return;
        }
        // Recursively sort halves of dest into src
        int destLow  = low;
        int destHigh = high;
        low  += off;
        high += off;
        int mid = (low + high) >>> 1;
        mergeSort(dest, src, low, mid, -off);
        mergeSort(dest, src, mid, high, -off);
        // If list is already sorted, just copy from src to dest.  This is an
        // optimization that results in faster sorts for nearly ordered lists.
        if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {
            System.arraycopy(src, low, dest, destLow, length);
            return;
        }
        // Merge sorted halves (now in src) into dest
        for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
            if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)
                dest[i] = src[p++];
            else
                dest[i] = src[q++];
        }
    }

這里方法中,swap方法是一個(gè)具體方法。每一個(gè)元素需要實(shí)現(xiàn)compareTo方法,“填補(bǔ)”模板方法的缺憾。

可能會(huì)有疑問(wèn),上面這個(gè)案例真的是一個(gè)模板方法嗎?

答,其符合模板方法的精神。這個(gè)模式的重點(diǎn)在于提供一個(gè)算法,并讓子類(lèi)實(shí)現(xiàn)某些步驟。而數(shù)組的排序做法很明顯地并非如此!但是,我們都知道。Java api中的模式并非總是如同教科書(shū)例子一般地中規(guī)中矩,為了符合當(dāng)前的環(huán)境和實(shí)現(xiàn)的約束,它們總是要被適當(dāng)?shù)匦薷?。這個(gè)Arrays類(lèi)sort方法的設(shè)計(jì)者受到一些約束。通常我們無(wú)法設(shè)計(jì)一個(gè)類(lèi)繼承Java數(shù)組,而sort()方法希望能夠適用于所有的數(shù)組(每個(gè)數(shù)組都是不同的類(lèi))。所以它們定義了一個(gè)靜態(tài)方法,而由被排序的對(duì)象內(nèi)的每個(gè)元素自行提供比較大小的算法部分。所以,這雖然不是教科書(shū)上的模板方法,但它的實(shí)現(xiàn)仍然符合模板方法模式的精神。再者,由于不需要基礎(chǔ)數(shù)組就可以使用這個(gè)方法,這樣使得排序變得更有彈性、更有用。

另外一個(gè)案例是java.io的InputStream類(lèi)有一個(gè)read()方法,是由子類(lèi)實(shí)現(xiàn)的,而這個(gè)方法又會(huì)被read(byte b[], int off, int len)模板方法使用。

模板方法模式的注意事項(xiàng)和細(xì)節(jié)

基本思想是:算法只存在于一個(gè)地方,也就是在父類(lèi)中,容易修改。需要修改算法時(shí),只要修改父類(lèi)的模板方法或者已經(jīng)實(shí)現(xiàn)的某些步驟,子類(lèi)就會(huì)繼承這些修改。

實(shí)現(xiàn)了最大化代碼復(fù)用。父類(lèi)的模板方法和已實(shí)現(xiàn)的某些步驟會(huì)被子類(lèi)繼承而直接使用。 既統(tǒng)一了算法,也提供了很大的靈活性。父類(lèi)的模板方法確保了算法的結(jié)構(gòu)保持不變,同時(shí)由子類(lèi)提供部分步驟的實(shí)現(xiàn)。

該模式的不足之處:每一個(gè)不同的實(shí)現(xiàn)都需要一個(gè)子類(lèi)實(shí)現(xiàn),導(dǎo)致類(lèi)的個(gè)數(shù)增加,使得系統(tǒng)更加龐大。一般模板方法都加上final 關(guān)鍵字, 防止子類(lèi)重寫(xiě)模板方法。

模板方法模式使用場(chǎng)景:當(dāng)要完成在某個(gè)過(guò)程,該過(guò)程要執(zhí)行一系列步驟,這一系列的步驟基本相同,但其個(gè)別步驟在實(shí)現(xiàn)時(shí)可能不同,通??紤]用模板方法模式來(lái)處理。

到此這篇關(guān)于Java設(shè)計(jì)模式之模板方法模式Template Method Pattern詳解的文章就介紹到這了,更多相關(guān)Java模板方法模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java排序算法總結(jié)之選擇排序

    Java排序算法總結(jié)之選擇排序

    這篇文章主要介紹了Java排序算法總結(jié)之選擇排序,較為詳細(xì)的分析了選擇排序的原理與java實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2015-05-05
  • mybatis實(shí)體類(lèi)字段大小寫(xiě)及字段獲取不到值問(wèn)題

    mybatis實(shí)體類(lèi)字段大小寫(xiě)及字段獲取不到值問(wèn)題

    這篇文章主要介紹了mybatis實(shí)體類(lèi)字段大小寫(xiě)及字段獲取不到值問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Spring依賴注入和控制反轉(zhuǎn)詳情

    Spring依賴注入和控制反轉(zhuǎn)詳情

    這篇文章主要介紹了Spring依賴注入和控制反轉(zhuǎn)詳情,控制反轉(zhuǎn)是面向?qū)ο缶幊讨惺褂玫男g(shù)語(yǔ),通過(guò)該術(shù)語(yǔ),對(duì)象或?qū)ο蠹目刂茩?quán)被賦予框架或由框架提供的容器。下文更多相關(guān)內(nèi)容需要的小伙伴可以參考一下
    2022-05-05
  • Java 敏感詞檢測(cè)工具的實(shí)現(xiàn)

    Java 敏感詞檢測(cè)工具的實(shí)現(xiàn)

    本文介紹了Java敏感詞檢測(cè)工具的使用方法,包括依賴引入、核心方法使用實(shí)例、常規(guī)用法、自定義替換檢測(cè)策略等內(nèi)容,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-11-11
  • Springboot整合策略模式詳解

    Springboot整合策略模式詳解

    這篇文章主要介紹了Springboot整合策略模式詳解的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • 解析和解決org.springframework.beans.factory.NoSuchBeanDefinitionException異常問(wèn)題

    解析和解決org.springframework.beans.factory.NoSuchBeanDefinitionE

    這篇文章主要介紹了解析和解決org.springframework.beans.factory.NoSuchBeanDefinitionException異常問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • Mybatis-Plus中updateById方法不能更新空值問(wèn)題解決

    Mybatis-Plus中updateById方法不能更新空值問(wèn)題解決

    本文主要介紹了Mybatis-Plus中updateById方法不能更新空值問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • Quarkus集成apollo配置中心

    Quarkus集成apollo配置中心

    這篇文章主要介紹了Quarkus集成apollo配置中心,文中詳細(xì)的講解了Quarkus的config構(gòu)成,以及apollo集成實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2022-02-02
  • Java生成二維碼的實(shí)現(xiàn)方式匯總

    Java生成二維碼的實(shí)現(xiàn)方式匯總

    本文將基于Spring Boot介紹兩種生成二維碼的實(shí)現(xiàn)方式,一種是基于Google開(kāi)發(fā)工具包,另一種是基于Hutool來(lái)實(shí)現(xiàn),下面我們將基于Spring Boot,并采用兩種方式實(shí)現(xiàn)二維碼的生成,對(duì)于每一種方式還提供兩種類(lèi)型的二維碼返回形式,需要的朋友可以參考下
    2023-09-09
  • Java中精確的浮點(diǎn)運(yùn)算操作示例

    Java中精確的浮點(diǎn)運(yùn)算操作示例

    這篇文章主要介紹了Java中精確的浮點(diǎn)運(yùn)算操作方法,結(jié)合具體實(shí)例形式分析了java浮點(diǎn)數(shù)運(yùn)算的相關(guān)函數(shù)、使用技巧與注意事項(xiàng),需要的朋友可以參考下
    2017-06-06

最新評(píng)論

安阳市| 沙洋县| 进贤县| 开阳县| 页游| 大余县| 定西市| 乐陵市| 泰州市| 蓝山县| 丘北县| 湘阴县| 南木林县| 天台县| 鄂伦春自治旗| 东兰县| 东方市| 涪陵区| 嘉祥县| 沁水县| 兴安盟| 商城县| 淮安市| 乌什县| 定兴县| 白朗县| 星子县| 安仁县| 出国| 内江市| 南陵县| 余庆县| 岳西县| 普安县| 宁乡县| 阿拉尔市| 凯里市| 翁牛特旗| 昆山市| 浠水县| 西藏|