javaweb學習28:郵件傳送原理及實現
阿新 • • 發佈:2022-04-06
策略模式屬於行為型模式,是使用最多的設計模式之一;其作用是針對一組演算法,將每一個演算法封裝到具體共同介面的獨立的類種,從而使得他們可以相互轉化。策略模式使得演算法可以在不影響到客戶端得情況下發生變化。
在開發過程中,經常會遇到某種業務存在多種策略可供選擇的情況,比如超市促銷打折,旅遊出行方案等。對於這一類的業務,按照傳統的方法,主要有以下兩種方案:
- 所有的業務邏輯都放在客戶端裡面。客戶端利用條件選擇語句決定使用哪一個演算法。這樣一來,客戶端程式碼會變得複雜和難以維護。
- 客戶端可以利用繼承的辦法在子類裡面實現不同的行為,但是這樣會使得環境和行為緊密耦合在一起。強耦合會使兩者不能單獨演化。
其實使用策略模式
當準備在一個系統裡使用策略模式時,首先必須找到需要包裝的演算法,看看演算法是否可以從環境中分割開來,最後再考察這些演算法是否會在以後發生變化。
策略模式的UML類圖如下:
由上圖可以看出,策略模式主要涉及到抽象策略角色、具體策略角色、環境角色三種角色:
- 抽象策略角色:通常由一個介面或抽象類實現,次角色給出所有的具體策略類所需的介面
- 具體策略角色:包裝了相關的演算法或行為
- 環境角色:持有一個策略類的引用
圖書折扣的例子
在一個購買圖書的系統中,主要由一些幾種不同的折扣:
折扣一(NoDiscountStrategy):對有些圖書沒有折扣。折扣演算法物件返還0作為折扣值。
折扣二(FlatRateStrategy):對有些圖書提供一個固定量值為1元的折扣。
折扣三(PercentageStrategy):對有些圖書提供一個百分比的折扣,比如本書價格為 20元,折扣百分比為7%,那麼折扣值就是20×7%=1.4(元)。
例子的UML類圖:
抽象策略角色:
package com.charon.strategy;
/**
* @className: DiscountStrategy
* @description:
* @author: charon
* @create: 2022-04-10 11:48
*/
public abstract class DiscountStrategy {
/**
* 價格
*/
private double price = 0;
/**
* 數量
*/
private int copies;
public DiscountStrategy() {
}
public DiscountStrategy(double price, int copies) {
this.price = price;
this.copies = copies;
}
/**
* 計算價格的策略方法
* @return
*/
abstract double calcDiscount();
/**
* Gets the value of price
*
* @return the value of price
*/
public double getPrice() {
return price;
}
/**
* Gets the value of copies
*
* @return the value of copies
*/
public int getCopies() {
return copies;
}
}
具體策略角色:
package com.charon.strategy;
/**
* @className: NoDiscountStrategy
* @description:
* @author: charon
* @create: 2022-04-10 11:48
*/
public class NoDiscountStrategy extends DiscountStrategy{
@Override
double calcDiscount() {
return 0;
}
}
package com.charon.strategy;
/**
* @className: FlatRateStrategy
* @description:
* @author: charon
* @create: 2022-04-10 11:48
*/
public class FlatRateStrategy extends DiscountStrategy{
/**
* 折扣金額
*/
private int discountPrice;
public FlatRateStrategy(double price, int copies) {
super(price,copies);
}
/**
* Sets the discountPrice
*
* @param discountPrice discountPrice
*/
public void setDiscountPrice(int discountPrice) {
this.discountPrice = discountPrice;
}
@Override
double calcDiscount() {
return discountPrice * getCopies();
}
}
package com.charon.strategy;
/**
* @className: PercentageStrategy
* @description:
* @author: charon
* @create: 2022-04-10 11:49
*/
public class PercentageStrategy extends DiscountStrategy{
/**
* 折扣百分比
*/
private double discountPercent;
public PercentageStrategy(double price, int copies) {
super(price, copies);
}
/**
* Sets the discountPercent
*
* @param discountPercent discountPercent
*/
public void setDiscountPercent(double discountPercent) {
this.discountPercent = discountPercent;
}
@Override
double calcDiscount() {
return getCopies() * getPrice() * discountPercent;
}
}
環境角色類:
package com.charon.strategy;
/**
* @className: Book
* @description:
* @author: charon
* @create: 2022-04-10 12:15
*/
public class Book {
/**
* 圖書名稱
*/
private String name;
/**
* 折扣型別
*/
private DiscountStrategy strategy;
public Book(String name, DiscountStrategy strategy) {
this.name = name;
this.strategy = strategy;
}
/**
* Sets the strategy
*
* @param strategy strategy
*/
public void setStrategy(DiscountStrategy strategy) {
this.strategy = strategy;
}
public void getDiscount(){
System.out.println("圖書名稱:《" + name + "》,折扣演算法為:"+ strategy.getClass() +",折扣價格為:" + strategy.calcDiscount());
}
}
客戶端角色:
package com.charon.strategy;
/**
* @className: Client
* @description:
* @author: charon
* @create: 2022-04-10 12:14
*/
public class Client {
public static void main(String[] args) {
Book book1 = new Book("java設計模式", new NoDiscountStrategy());
book1.getDiscount();
FlatRateStrategy rateStrategy = new FlatRateStrategy(23.0, 5);
rateStrategy.setDiscountPrice(1);
Book book2 = new Book("java與模式",rateStrategy);
book2.getDiscount();
System.out.println("修改《java與模式》的折扣演算法:");
PercentageStrategy percentageStrategy = new PercentageStrategy(23, 5);
percentageStrategy.setDiscountPercent(0.07);
book2.setStrategy(percentageStrategy);
book2.getDiscount();
}
}
列印:
圖書名稱:《java設計模式》,折扣演算法為:class com.charon.strategy.NoDiscountStrategy,折扣價格為:0.0
圖書名稱:《java與模式》,折扣演算法為:class com.charon.strategy.FlatRateStrategy,折扣價格為:5.0
修改《java與模式》的折扣演算法:
圖書名稱:《java與模式》,折扣演算法為:class com.charon.strategy.PercentageStrategy,折扣價格為:8.05
策略模式的主要優點如下:
- 多重條件語句不易維護,而使用策略模式可以避免使用多重條件語句,如 if...else 語句、switch...case 語句。
- 策略模式提供了一系列的可供重用的演算法族,恰當使用繼承可以把演算法族的公共程式碼轉移到父類裡面,從而避免重複的程式碼。
- 策略模式可以提供相同行為的不同實現,客戶可以根據不同時間或空間要求選擇不同的。
- 策略模式提供了對開閉原則的完美支援,可以在不修改原始碼的情況下,靈活增加新演算法。
- 策略模式把演算法的使用放到環境類中,而演算法的實現移到具體策略類中,實現了二者的分離。
策略模式的主要缺點如下:
- 客戶端必須理解所有策略演算法的區別,以便適時選擇恰當的演算法類。
- 策略模式造成很多的策略類,增加維護難度。
策略模式的應用場景
策略模式在很多地方用到,如 Java SE 中的容器佈局管理就是一個典型的例項,Java SE 中的每個容器都存在多種佈局供使用者選擇。在程式設計中,通常在以下幾種情況中使用策略模式較多。
- 一個系統需要動態地在幾種演算法中選擇一種時,可將每個演算法封裝到策略類中。
- 一個類定義了多種行為,並且這些行為在這個類的操作中以多個條件語句的形式出現,可將每個條件分支移入它們各自的策略類中以代替這些條件語句。
- 系統中各演算法彼此完全獨立,且要求對客戶隱藏具體演算法的實現細節時。
- 系統要求使用演算法的客戶不應該知道其操作的資料時,可使用策略模式來隱藏與演算法相關的資料結構。
- 多個類只區別在表現行為不同,可以使用策略模式,在執行時動態選擇具體要執行的行為。