策略模式(Stragety Pattern)
策略模式屬於行為型模式,它定義了一系列的演算法,並將每一個演算法封裝起來,而且使他們可以相互替換,讓演算法獨立於使用它的客戶而獨立變化。
使用原則模式可以把行為和環境分割開來。環境類負責維持和查詢行為類,各種演算法則在具體策略類中提供。
角色:
1、抽象策略(Strategy)
這是一個抽象角色,通常由一個介面或抽象類別實現。此角色給出所有的具體策略類所需的介面;
2、具體策略(Concrete Strategy)
實現抽象策略的具體策略類,封裝了相關的演算法或行為;
3、環境類(Context)
持有一個Strategy類的引用並可以根據邏輯選擇執行個體相應的策略。
樣本:
命名空間StragetyPattern中包含策略基類Tax以及它的8個實作類別,Context環境類持有策略基類。本樣本通過一個優雅的方式來計算個人所得稅。
C#開發筆記之04-如何用C#優雅的計算個人所得稅?
namespace StragetyPattern
public abstract class Tax { protected decimal TaxRate = 0; protected decimal QuickDeduction = 0; public virtual decimal Calculate(decimal income) { return income * TaxRate - QuickDeduction; }}
策略基類Tax,表示個人所得稅,TaxRate為稅率,QuickDeduction為速算扣除數,Calculate計算相應收入的個人所得稅。
public class Level0 : Tax { public Level0() { TaxRate = 0.00m; QuickDeduction = 0; }}
0級個人所得稅階梯,表示個人所得稅的初始狀態。
public class Level1 : Tax { public Level1() { TaxRate = 0.03m; QuickDeduction = 0; }}
1級個人所得稅階梯。
public class Level2 : Tax { public Level2() { TaxRate = 0.10m; QuickDeduction = 105; }}
2級個人所得稅階梯。
public class Level3 : Tax { public Level3() { TaxRate = 0.20m; QuickDeduction = 555; }}
3級個人所得稅階梯。
public class Level4 : Tax { public Level4() { TaxRate = 0.25m; QuickDeduction = 1005; }}
4級個人所得稅階梯。
public class Level5 : Tax { public Level5() { TaxRate = 0.30m; QuickDeduction = 2755; }}
5級個人所得稅階梯。
public class Level6 : Tax { public Level6() { TaxRate = 0.35m; QuickDeduction = 5505; }}
6級個人所得稅階梯。
public class Level7 : Tax { public Level7() { TaxRate = 0.45m; QuickDeduction = 13505; }}
7級個人所得稅階梯。
public class Context { private Tax _tax = null; private const decimal EXEMPTION_VALUE = 3500m; private List<decimal> _taxLevel = new List<decimal>{ 0, 1500, 4500, 9000, 35000, 55000, 80000, decimal.MaxValue }; private List<Type> _levels = new List<Type>(); private void GetLevels() { _levels = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(tp => tp.GetTypes() .Where(t => t.BaseType == typeof(Tax))) .ToList(); } public Context() { GetLevels(); } public Context Calculate(decimal income) { _tax = new Level0(); var result = income - EXEMPTION_VALUE; for(int i = 1; i <= _taxLevel.Count - 1; i++) { if(result > _taxLevel[i - 1] && result <= _taxLevel[i]) { _tax = (Tax)Activator.CreateInstance(_levels[i]); } } Console.WriteLine($"Income = {income}," + $"tax = {_tax.Calculate(result)}!"); return this; }}
環境類Context,首先需要維持對Tax的引用,EXEMPTION_VALUE表示免徵額(本例使用3500元),之後通過反射和一些技巧選擇相應的Tax實作類別來計算相應階梯的個人所得稅。
public class Program { private static Context _context = new Context(); public static void Main(string[] args) { _context.Calculate(2500.00m) .Calculate(4900.00m) .Calculate(5500.00m) .Calculate(7000.00m) .Calculate(10000.00m) .Calculate(16000.00m) .Calculate(43000.00m) .Calculate(70000.00m) .Calculate(100000.00m) .Calculate(4500.00m) .Calculate(1986.00m); Console.ReadKey(); }}
以上是調用方的代碼,Calculate經過特殊處理以支援方法鏈。以下是這個案例的輸出結果:
Income = 2500.00,tax = 0.0000!Income = 4900.00,tax = 42.0000!Income = 5500.00,tax = 95.0000!Income = 7000.00,tax = 245.0000!Income = 10000.00,tax = 745.0000!Income = 16000.00,tax = 2120.0000!Income = 43000.00,tax = 9095.0000!Income = 70000.00,tax = 17770.0000!Income = 100000.00,tax = 29920.0000!Income = 4500.00,tax = 30.0000!Income = 1986.00,tax = 0.0000!
優點:
1、策略類的等級結構定義了一個演算法或行為族,恰當使用繼承可以把公用的代碼移到父類裡面,從而避免重複的代碼;
2、繼承可以處理多種演算法或行為,可以避免使用多重條件轉移語句。
缺點:
1、用戶端必須知道所有的策略類,並自行決定使用哪一個策略類;
2、策略模式造成很多的策略類,造成“子類爆炸”。
使用情境:
1、如果在一個系統裡面有許多類,它們之間的區別僅在於它們的行為,那麼使用原則模式可以動態地讓一個對象在許多行為中選擇一種行為;
2、一個系統需要動態地在幾種演算法中選擇一種。
相關文章:
使用C/C++編寫PHP Extension
【c#教程】C# 資料類型
相關視頻:
什麼是設計模式-php進階設計模式視頻教程