目錄
- 策略模式
- 策略模式結構
- 策略模式應用場景
- 策略模式優缺點
- 練手題目
- 題目描述
- 輸入描述
- 輸出描述
- 題解
策略模式
策略模式,又稱政策模式,是一種行為型設計模式,它能讓你定義一系列算法,并將每種算法分別放入獨立的類中,以使算法的對象能夠相互替換。
策略模式結構
- 上下文(Context)維護指向具體策略的引用,且僅通過策略接口與該對象進行交流。
- 策略 (Strategy) 接口是所有具體策略的通用接口, 它聲明了一個上下文用于執行策略的方法。
- 具體策略 (Concrete Strategies) 實現了上下文所用算法的各種不同變體。
- 當上下文需要運行算法時, 它會在其已連接的策略對象上調用執行方法。 上下文不清楚其所涉及的策略類型與算法的執行方式。
- 客戶端 (Client) 會創建一個特定策略對象并將其傳遞給上下文。 上下文則會提供一個設置器以便客戶端在運行時替換相關聯的策略。
通用代碼結構示例
//策略接口聲明了某個算法各個不同版本間所共有的操作。
interface Strategy{...
}//具體策略會在遵循策略基礎接口的情況下實現算法。
class ConcreteStrategies implements Strategy{...
}//抽象生成器類
class Context{//抽象策略private Strategy strategy = null;//抽象策略設置具體策略public Context(Strategy s){this.strategy=s;}//封裝具體的方法...}//客戶端
public class Client{Stragety stragety = new ConcrateStrategies();Context context = new Context(Strategy);...
}
策略模式應用場景
-
當你想使用對象中各種不同的算法變體, 并希望能在運行時切換算法時, 可使用策略模式。
策略模式讓你能夠將對象關聯至可以不同方式執行特定子任務的不同子對象, 從而以間接方式在運行時更改對象行為。
-
當你有許多僅在執行某些行為時略有不同的相似類時,可使用策略模式。
策略模式讓你能將不同行為抽取到一個獨立類層次結構中, 并將原始類組合成同一個, 從而減少重復代碼。
-
如果算法在上下文的邏輯中不是特別重要, 使用該模式能將類的業務邏輯與其算法實現細節隔離開來。
策略模式讓你能將各種算法的代碼、 內部數據和依賴關系與其他代碼隔離開來。 不同客戶端可通過一個簡單接口執行算法, 并能在運行時進行切換。
-
當類中使用了復雜條件運算符以在同一算法的不同變體中切換時,可使用該模式。
策略模式將所有繼承自同樣接口的算法抽取到獨立類中, 因此不再需要條件語句。 原始對象并不實現所有算法的變體, 而是將執行工作委派給其中的一個獨立算法對象。
識別方法:策略模式可以通過允許嵌套對象完成實際工作的方法以及允許將該對象替換為不同對象的設置器來識別。
策略模式優缺點
優點:
- 你可以在運行時切換對象內的算法。
- 你可以將算法的實現和使用算法的代碼隔離開來。
- 你可以使用組合來代替繼承。
- 開閉原則。 你無需對上下文進行修改就能夠引入新的策略。
缺點:
- 如果你的算法極少發生改變,那么沒有任何理由引入新的類和接口。使用該模式只會讓程序過于復雜。
- 客戶端必須知曉策略間的不同——它需要選擇合適的策略。
- 許多現代編程語言支持函數類型功能, 允許你在一組匿名函數中實現不同版本的算法。 這樣, 你使用這些函數的方式就和使用策略對象時完全相同, 無需借助額外的類和接口來保持代碼簡潔。
練手題目
題目描述
小明家的超市推出了不同的購物優惠策略,你可以根據自己的需求選擇不同的優惠方式。其中,有兩種主要的優惠策略:
- 九折優惠策略:原價的90%。
- 滿減優惠策略:購物滿一定金額時,可以享受相應的減免優惠。
具體的滿減規則如下:
滿100元減5元
滿150元減15元
滿200元減25元
滿300元減40元
請你設計一個購物優惠系統,用戶輸入商品的原價和選擇的優惠策略編號,系統輸出計算后的價格。
輸入描述
輸入的第一行是一個整數 N(1 ≤ N ≤ 20),表示需要計算優惠的次數。
接下來的 N 行,每行輸入兩個整數,第一個整數M( 0 < M < 400) 表示商品的價格, 第二個整數表示優惠策略,1表示九折優惠策略,2表示滿減優惠策略
輸出描述
每行輸出一個數字,表示優惠后商品的價格
題解
1、初次解決思路,簡單的策略模式實現。
import java.util.Scanner;interface Strategy {void preferentialMethod(int price);
}class ConcreteStrategy1 implements Strategy {public void preferentialMethod(int price) {double discountedPrice = 0.9 * price;System.out.println((int) discountedPrice);}
}class ConcreteStrategy2 implements Strategy {public void preferentialMethod(int price) {if (price >= 300) {price = price - 40;} else if (price < 300 && price >=200) {price = price - 25;} else if (price < 200 && price >= 150) {price = price - 15;} else if (price <150 && price >= 100) {price = price - 5;}System.out.println(price);}
}class Context {private Strategy strategy;public Context(Strategy strategy) {this.strategy = strategy;}public void executeStrategy(int price) {strategy.preferentialMethod(price);}
}public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);try {int num = scanner.nextInt();scanner.nextLine(); for (int i = 0; i < num; i++) {String input = scanner.nextLine();String[] parts = input.split(" ");if (parts.length != 2) {System.out.println("輸入錯誤!");break;}int price = Integer.parseInt(parts[0]);int type = Integer.parseInt(parts[1]);Context context = null;switch (type) {case 1:context = new Context(new ConcreteStrategy1());break;case 2:context = new Context(new ConcreteStrategy2());break;default:System.out.println("無效選擇,請輸入1或2");continue;}context.executeStrategy(price);}} catch (Exception e) {System.out.println("An error occurred: " + e.getMessage());} finally {scanner.close();}}
}
2、優化后,使用策略枚舉類實現。
import java.util.Scanner;interface Strategy {void preferentialMethod(int price);
}//策略枚舉類
enum DiscountStrategy implements Strategy {STRATEGY1 {@Overridepublic void preferentialMethod(int price) {double discountedPrice = 0.9 * price;System.out.println((int) discountedPrice);}},STRATEGY2 {@Overridepublic void preferentialMethod(int price) {int[][] discountRules = {{300, 40},{200, 25},{150, 15},{100, 5}};for (int[] rule : discountRules) {if (price >= rule[0]) {price -= rule[1];break;}}System.out.println(price);}};public static DiscountStrategy fromType(int type) {switch (type) {case 1:return STRATEGY1;case 2:return STRATEGY2;default:throw new IllegalArgumentException("無效選擇,請輸入1或2");}}
}class Context {private Strategy strategy;public Context(Strategy strategy) {this.strategy = strategy;}public void executeStrategy(int price) {strategy.preferentialMethod(price);}
}public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);try {int num = scanner.nextInt();scanner.nextLine();for (int i = 0; i < num; i++) {try {String input = scanner.nextLine();String[] parts = input.split(" ");if (parts.length != 2) {System.out.println("輸入錯誤!");continue;}int price = Integer.parseInt(parts[0]);int type = Integer.parseInt(parts[1]);DiscountStrategy strategy = DiscountStrategy.fromType(type);Context context = new Context(strategy);context.executeStrategy(price);} catch (NumberFormatException e) {System.out.println("輸入格式錯誤,請輸入有效的價格和類型!");} catch (IllegalArgumentException e) {System.out.println(e.getMessage());}}} catch (Exception e) {System.out.println("An error occurred: " + e.getMessage());} finally {scanner.close();}}
}