策略模式是一種行為型設計模式,它定義了一系列的演算法,並將每個演算法封裝到獨立的類中,使它們可以互相替換。策略模式使得演算法可以獨立於客戶端而變化,客戶端可以根據需要選擇不同的演算法。
策略模式有三個主要角色:
-
環境類(Context):它持有一個策略物件的引用,並在需要的時候呼叫策略物件的方法。環境類可以根據需要動態地替換策略物件。
-
抽象策略類(Strategy):定義了策略的抽象介面,通常包含一個或多個策略方法。
-
具體策略類(Concrete Strategy):實現了抽象策略介面,提供具體的演算法實現。
策略模式的工作原理如下:
-
環境類持有一個策略物件的引用,並在需要的時候呼叫策略物件的方法。
-
客戶端根據需要選擇具體的策略類,並將其傳遞給環境類。
-
環境類根據傳入的策略物件,呼叫相應的策略方法。
策略模式的優點包括:
-
提供了一種簡潔的方式來封裝和切換演算法,使得演算法可以獨立於客戶端變化。
-
可以避免使用大量的條件判斷語句,提高了程式碼的可讀性和可維護性。
-
可以透過繼承和介面的方式擴充套件新的策略類。
策略模式適用於以下場景:
-
當多個類只有在演算法或行為上有不同的情況下,可以使用策略模式。
-
當需要在執行時動態地選擇不同的演算法時,可以使用策略模式。
總結而言,策略模式透過將演算法封裝到獨立的策略類中,使得演算法可以獨立於客戶端變化。它提供了一種簡潔的方式來切換和封裝演算法,提高了程式碼的可讀性和可維護性。
案例場景:
在商場收銀系統中,可以正常收費,即按照單價*數量得出價格,遇到活動時可以打折收費和返利收費,從而計算價格。
Strategy
/// <summary> /// 抽象策略角色 /// </summary> public abstract class PayBase { /// <summary> /// 結算計算方式 /// </summary> /// <param name="money"></param> /// <returns></returns> public abstract double Calc(double money); }
Concrete Strategy
/// <summary> /// 正常收費 /// </summary> public class NormalPay : PayBase { public override double Calc(double money) { return money; } }
/// <summary> /// 折扣收費 /// </summary> public class RebatePay : PayBase { private double rebate = 1; public RebatePay(double rebate) { if(rebate < 0 || rebate > 1) { throw new ArgumentException("折扣在0-1之間"); } this.rebate = rebate; } public override double Calc(double money) { return money * rebate; } }
/// <summary> /// 滿減收費 /// </summary> public class SubtractPay : PayBase { public int level = 0; public int subMoney = 0; public SubtractPay(int level, int subMoney) { this.level = level; this.subMoney = subMoney; } public override double Calc(double money) { int v = (int)(money / level); return money - v * subMoney; } }
Context
/// <summary> /// 打折 /// </summary> public class PayContext { private PayBase Pay = new NormalPay(); public void SetPayMode(PayBase pay) { Pay = pay; } public double GetResult(double money) { return Pay.Calc(money); } }
呼叫
internal class Client { public void Start() { double sumMoney = 10 * 18.5;//數量*單價=總價 double realMoney = 0;//最終支付費用 Console.WriteLine($"應付:{sumMoney}"); PayContext context = new PayContext(); //正常收費 realMoney = context.GetResult(sumMoney); Console.WriteLine($"正常收費:{realMoney}"); //扣扣收費 context.SetPayMode(new RebatePay(0.85)); realMoney = context.GetResult(sumMoney); Console.WriteLine($"扣扣收費:{realMoney}"); //滿減收費 context.SetPayMode(new SubtractPay(100,5)); realMoney = context.GetResult(sumMoney); Console.WriteLine($"減收費:{realMoney}"); } }
static void Main(string[] args) { new Client().Start(); Console.ReadKey(); }