经典的策略模式如下图所示:
让我解释一下这幅图的含义,IContext是上下文的接口类,IStrategy是策略的接口,IStrategy依赖于IContext,也就是IContext里面存有一个IStrategy的策略字段。
其实策略模式说白了,就像诸葛亮给刘备的锦囊妙计一样,遇到一种具体的情况,采取一种相应的策略。也就像我们平时会观察天气,根据今天有没有下雨,选择要不要打伞,下雨的话,那么打伞;不下雨就不打伞。
下面我们用代码来演示一下经典的策略模式。我们将要做的是,从一个数组中提取一个值,这个值的提取要根据用户的选择,也就是我们要根据用户的选择提取对应的值。假设用户有三种选择,选最大值,最小值,选第一个值。
1、首先我们要实现公共接口
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace BangWorks.PractcalPattern.StategyPattern.Classic { interface IStrategy { /// <summary> /// 按照算法的要求,将数据提取出来 /// </summary> /// <param name="Data">数组</param> /// <returns></returns> int PickUp(int[] Data); } interface IContext { IStrategy Strategy { get; set; } int GetData(int[] data); } }
2、实现相应的策略类
/// <summary> /// 取最大值 /// </summary> class DescentSortStrategy:IStrategy { int IStrategy.PickUp(int[] Data) { Array.Sort<int>(Data); return Data[Data.Length-1]; } } /// <summary> /// 取第一个值 /// </summary> class FirstDataStrategy:IStrategy { public int PickUp(int[] Data) { return Data[0]; } } /// <summary> /// 取最小值 /// </summary> class AscentStrategy:IStrategy { int IStrategy.PickUp(int[] Data) { Array.Sort<int>(Data); return Data[0]; } }
3、最后,我们利用策略模式来切换策略
/// <summary> ///GetData 的测试 ///</summary> [TestMethod()] public void GetDataTest() { IStrategy mStrategy = new FirstDataStrategy(); IContext target = CreateIContext(); int[] data = new int[]{7,2,5,8,0,1}; //切换成取第一个值的 target.Strategy = mStrategy; int expected = 7; int actual; actual = target.GetData(data); Assert.AreEqual(expected, actual); //切换成取最小值的 target.Strategy = new AscentStrategy(); expected = 0; actual = target.GetData(data); Assert.AreEqual(expected, actual); //切换成取最大值的 target.Strategy = new DescentSortStrategy(); expected = 8; actual = target.GetData(data); Assert.AreEqual(expected, actual); }
最后附上完整的单元测试类
1 using BangWorks.PractcalPattern.StategyPattern.Classic; 2 using Microsoft.VisualStudio.TestTools.UnitTesting; 3 using System; 4 5 namespace BangWork.PractcalPattern.Concept.InderTest 6 { 7 8 9 /// <summary> 10 ///这是 IContextTest 的测试类,旨在 11 ///包含所有 IContextTest 单元测试 12 ///</summary> 13 [TestClass()] 14 public class IContextTest:IContext 15 { 16 /// <summary> 17 /// 取最大值 18 /// </summary> 19 class DescentSortStrategy:IStrategy 20 { 21 int IStrategy.PickUp(int[] Data) 22 { Array.Sort<int>(Data); 23 return Data[Data.Length-1]; 24 25 } 26 } 27 /// <summary> 28 /// 取第一个值 29 /// </summary> 30 class FirstDataStrategy:IStrategy 31 { 32 33 public int PickUp(int[] Data) 34 { 35 return Data[0]; 36 } 37 } 38 /// <summary> 39 /// 取最小值 40 /// </summary> 41 class AscentStrategy:IStrategy 42 { 43 int IStrategy.PickUp(int[] Data) 44 { 45 Array.Sort<int>(Data); 46 return Data[0]; 47 } 48 } 49 private TestContext testContextInstance; 50 51 /// <summary> 52 ///获取或设置测试上下文,上下文提供 53 ///有关当前测试运行及其功能的信息。 54 ///</summary> 55 public TestContext TestContext 56 { 57 get 58 { 59 return testContextInstance; 60 } 61 set 62 { 63 testContextInstance = value; 64 } 65 } 66 67 #region 附加测试特性 68 // 69 //编写测试时,还可使用以下特性: 70 // 71 //使用 ClassInitialize 在运行类中的第一个测试前先运行代码 72 //[ClassInitialize()] 73 //public static void MyClassInitialize(TestContext testContext) 74 //{ 75 //} 76 // 77 //使用 ClassCleanup 在运行完类中的所有测试后再运行代码 78 //[ClassCleanup()] 79 //public static void MyClassCleanup() 80 //{ 81 //} 82 // 83 //使用 TestInitialize 在运行每个测试前先运行代码 84 //[TestInitialize()] 85 //public void MyTestInitialize() 86 //{ 87 //} 88 // 89 //使用 TestCleanup 在运行完每个测试后运行代码 90 //[TestCleanup()] 91 //public void MyTestCleanup() 92 //{ 93 //} 94 // 95 #endregion 96 97 98 internal virtual IContext CreateIContext() 99 { 100 // TODO: 实例化相应的具体类。 101 IContext target = new IContextTest(); 102 return target; 103 } 104 105 /// <summary> 106 ///GetData 的测试 107 ///</summary> 108 [TestMethod()] 109 public void GetDataTest() 110 { 111 IStrategy mStrategy = new FirstDataStrategy(); 112 113 IContext target = CreateIContext(); 114 int[] data = new int[]{7,2,5,8,0,1}; 115 116 //切换成取第一个值的 117 target.Strategy = mStrategy; 118 int expected = 7; 119 int actual; 120 actual = target.GetData(data); 121 Assert.AreEqual(expected, actual); 122 //切换成取最小值的 123 target.Strategy = new AscentStrategy(); 124 expected = 0; 125 actual = target.GetData(data); 126 Assert.AreEqual(expected, actual); 127 128 //切换成取最大值的 129 target.Strategy = new DescentSortStrategy(); 130 expected = 8; 131 actual = target.GetData(data); 132 Assert.AreEqual(expected, actual); 133 } 134 135 /// <summary> 136 ///Strategy 的测试 137 ///</summary> 138 [TestMethod()] 139 public void StrategyTest() 140 { 141 IContext target = CreateIContext(); // TODO: 初始化为适当的值 142 IStrategy expected = null; // TODO: 初始化为适当的值 143 IStrategy actual; 144 target.Strategy = expected; 145 actual = target.Strategy; 146 Assert.AreEqual(expected, actual); 147 Assert.Inconclusive("验证此测试方法的正确性。"); 148 } 149 150 public IStrategy Strategy 151 { 152 get; 153 set; 154 } 155 156 public int GetData(int[] data) 157 { 158 return this.Strategy.PickUp(data); 159 } 160 } 161 }