什麼是計算機、Dos的常用命令、JAVA的特性和優勢
模板方法模式屬於行為型模式,定義一個操作中的演算法骨架,而將演算法的一些步驟延遲到子類中,使得子類可以不改變該演算法結構的情況下重定義該演算法的某些特定步驟,不同的子類可以以不同的方式實現這些抽象方法。從而對剩餘邏輯有不同的實現。模版方法模式是基於繼承的程式碼複用的基本技術,模版方法模式的結構和用法也是面向物件設計的核心。
模板方法模式的UML類圖如下:
從上圖可以看出,模板方法模式主要有抽象類角色、具體子類角色兩種角色:
-
抽象類角色:
定義了一個或多個抽象操作,以便讓子類實現。這些抽象操作叫做基本操作,它們是一個頂級邏輯的組成步驟。
定義並實現了一個模版方法。這個模版方法一般是一個具體方法,它給出了一個頂級邏輯的骨架,而邏輯的組成步驟在相應的抽象操作中,推遲到子類實現。頂級邏輯也有可能呼叫一些具體方法。
-
具體子類角色:
實現父類所定義的一個或多個抽象方法,它們是一個頂級邏輯的組成步驟。
每一個抽象模版角色都可以有任意多個具體模版角色與之對應,而每一個具體模版角色都可以給出這些抽象方法(也就是頂級邏輯的組成步驟〉的不同實現,從而使得頂級邏輯的實現各不相同。
銀行存款例子
一個系統需要計算存款利息,主要有兩種存款賬號,即貨幣市場賬戶(Money Market ACcount)和定期賬戶(CDAccount);這兩種賬戶的存款利率是不通的,因此,在計算一個賬戶的存款利息額的時候,必須分割槽兩種不同的賬戶型別。
那麼在這個系統中,主要有兩個方法,一是確定賬戶的型別,二是確定利息的百分比。在這裡就可以使用模板方法在抽象類中定義兩個基本方法,然後有子類根據賬號型別的不同而給出具體的方法。
其UML類圖如下:
抽象類:
package com.charon.template; /** * @className: Account * @description: * @author: charon * @create: 2022-03-26 14:57 */ public abstract class Account { private String accountNum; /** * 無參構造,幫助子類初始化 * 如果沒有顯示宣告父類的無參的構造方法,系統會自動預設生成一個無參構造方法。 * 但是,如果聲明瞭一個有參的構造方法,而沒有宣告無參的構造方法,這時系統不會動預設生成一個無參構造方法。 */ public Account() { } public Account(String accountNum) { this.accountNum = accountNum; } /** * 模板方法,計算利息的數額 * 使用final修飾,可以防止子類重寫模板方法 * @return */ public final double calcInterest(){ double interestRate = calcInterestRate(); String accountType = calcAccountType(); double amount = getAmount(accountType,accountNum); return interestRate * amount; } /** * 獲取賬戶金額 * @param accountType 賬戶型別 * @param accountNum 賬號 * @return */ protected double getAmount(String accountType, String accountNum){ // 從資料庫中獲取該賬戶的金額,這裡直接返回一個 return 5000; } /** * 計算賬戶型別 */ protected abstract String calcAccountType(); /** * 計算利息利率 * @return */ protected abstract double calcInterestRate(); }
具體子類:
package com.charon.template;
/**
* @className: MoneyMarketAccount
* @description:
* @author: charon
* @create: 2022-03-26 15:12
*/
public class MoneyMarketAccount extends Account{
@Override
protected String calcAccountType() {
return "Money Market";
}
@Override
protected double calcInterestRate() {
return 0.045;
}
}
package com.charon.template;
/**
* @className: CDAccount
* @description:
* @author: charon
* @create: 2022-03-26 15:22
*/
public class CDAccount extends Account {
@Override
protected String calcAccountType() {
return "CD";
}
@Override
protected double calcInterestRate() {
return 0.065;
}
}
客戶端呼叫:
package com.charon.template;
/**
* @className: Client
* @description:
* @author: charon
* @create: 2022-03-25 23:44
*/
public class Client {
public static void main(String[] args) {
Account mmAccount = new MoneyMarketAccount();
System.out.println("貨幣市場賬號的利息是:" + mmAccount.calcInterest());
Account cdAccount = new CDAccount();
System.out.println("定期賬號的利息是:" + cdAccount.calcInterest());
}
}
列印:
貨幣市場賬號的利息是:225.0
定期賬號的利息是:325.0
模板方法模式的主要優點如下:
- 它封裝了不變部分,擴充套件可變部分。它把認為是不變部分的演算法封裝到父類中實現,而把可變部分演算法由子類繼承實現,便於子類繼續擴充套件。
- 它在父類中提取了公共的部分程式碼,便於程式碼複用。
- 部分方法是由子類實現的,因此子類可以通過擴充套件方式增加相應的功能,符合“開閉原則”。
模板方法模式的主要缺點如下:
- 對每個不同的實現都需要定義一個子類,這會導致類的個數增加,系統更加龐大,設計也更加抽象,間接地增加了系統實現的複雜度。
- 父類中的抽象方法由子類實現,子類執行的結果會影響父類的結果,這導致一種反向的控制結構,它提高了程式碼閱讀的難度。
- 由於繼承關係自身的缺點,如果父類新增新的抽象方法,則所有子類都要改一遍。
模式的應用場景
模板方法模式通常適用於以下場景。
- 演算法的整體步驟很固定,但其中個別部分易變時,這時候可以使用模板方法模式,將容易變的部分抽象出來,供子類實現。
- 當多個子類存在公共的行為時,可以將其提取出來並集中到一個公共父類中以避免程式碼重複。首先,要識別現有程式碼中的不同之處,並且將不同之處分離為新的操作。最後,用一個呼叫這些新的操作的模板方法來替換這些不同的程式碼。
- 當需要控制子類的擴充套件時,模板方法只在特定點呼叫鉤子操作,這樣就只允許在這些點進行擴充套件。