设计模式(一)简单工厂与策略模式
设计模式用 UML 类图来描述比较普遍。如样例所示,注意前面的符号:
‘+’ 表示 Public,‘-’ 表示 Private,‘#’ 表示 Protected;
继承关系用 空心三角形 + 实线 来表示;
实现接口用 空心三角形 + 虚线 来表示;
关联关系用 实线箭头 来表示(当一个类需要 ‘知道’ 另一个类);
聚合关系用 空心的菱形 + 实线箭头 来表示(聚合(Aggregation)表示一种弱的 ‘拥有’ 关系,体现的是 A 对象可以包含 B 对象,但 B 对象不是 A 对象的一部分);
合成关系用 实心的菱形 + 实线箭头 来表示(合成(Composition),或称组合,是一种强的 ‘拥有’ 关系,体现了严格的部分与整体的关系,部分和整体的生命周期是一样的);如果一个类可能有无数个实例,则就用 ‘n’ 来表示。关联关系、聚合关系也可以有基数的。
依赖关系用 虚线箭头 来表示(Dependency )。

面向对象的编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类。
1 interface IFly 2 { 3 void Fly(); 4 } 5 interface ILanguage 6 { 7 void Speak(); 8 } 9 // 继承动物类 10 class Bird : Animal 11 { 12 } 13 // 实现飞翔接口 14 class WideGoose : IFly 15 { 16 } 17 // 企鹅引用到气候对象 18 class Penguin : Bird 19 { 20 private Climate climate; 21 } 22 // 雁群 类中有 大雁数组 对象 23 class WideGooseAggregate 24 { 25 private WideGoose[] arrayWideGoose; 26 } 27 // 在鸟类初始化时,实例化翅膀Wing,它们之间同时生成 28 class Bird 29 { 30 private Wing wing; 31 public Bird() 32 { 33 wing = new Wing(); 34 } 35 } 36 abstract class Animal 37 { 38 public Metabolism(Oxygen oxygen, Water water) 39 { 40 } 41 }
一、简单工厂模式

代码实现
1 // 运算类 2 public class Operation 3 { 4 private double _numberA = 0; 5 private double _numberB = 0; 6 7 public double NumberA 8 { 9 get{ return _numberA; } 10 set{ _numberA = value; } 11 } 12 13 public double NumberB 14 { 15 get{ return _numberB; } 16 set{ _numberB = value; } 17 } 18 19 public virtual double GetResult() 20 { 21 double result = 0; 22 return result; 23 } 24 } 25 // 加法类,继承 运算类 26 class OperationAdd : Operation 27 { 28 public override double GetResult() 29 { 30 double result = 0; 31 result = NumberA + NumberB; 32 return result; 33 } 34 } 35 // 减法类,继承 运算类 36 class OperationSub : Operation 37 { 38 public override double GetResult() 39 { 40 double result = 0; 41 result = NumberA - NumberB; 42 return result; 43 } 44 } 45 // 乘法类,继承 运算类 46 class OperationMul : Operation 47 { 48 public override double GetResult() 49 { 50 double result = 0; 51 result = NumberA * NumberB; 52 return result; 53 } 54 } 55 // 除法类,继承 运算类 56 class OperationDiv : Operation 57 { 58 public override double GetResult() 59 { 60 double result = 0; 61 if(NumberB == 0) 62 throw new Exception("除数不能为零"); 63 result = NumberA / NumberB; 64 return result; 65 } 66 } 67 // 68 punlic class OperationFactory 69 { 70 public static Operation createOperate(string operate) 71 { 72 Operation oper = null; 73 switch(operate) 74 { 75 case "+": 76 oper = new OperationAdd(); 77 break; 78 case "-": 79 oper = new OperationSub(); 80 break; 81 case "*": 82 oper = new OperationMul(); 83 break; 84 case "/": 85 oper = new OperationDiv(); 86 break; 87 } 88 return oper; 89 } 90 91 } 92 93 // 客户端代码 94 Operation oper; 95 oper = OperationFactory.createOperate("+"); 96 oper.NumberA = 1; 97 oper.NumberB = 1; 98 double result = oper.GetResult();

代码结构图
1 // 现金收费抽象类 2 abstract class CashSuper 3 { 4 // 现金收取超类的抽象方法,收取现金,参数为原价,返回为当前价 5 public abstract double acceptCash(double money) 6 } 7 // 正常收费子类 8 class CashNormal : CashSuper 9 { 10 // 正常收费,原价返回 11 public override double acceptCash(double money) 12 { 13 return money; 14 } 15 } 16 // 打折收费子类 17 class CashRebate : CashSuper 18 { 19 private double moneyRebate = 1d; 20 21 public CashRebate(string moneyRebate) 22 { 23 // 打折收费,初始化时,必需要输入折扣率,如八折,就是 0.8 24 this.moneyRebate = double.Parse(moneyRebate); 25 } 26 27 public override double accepeCash(double money) 28 { 29 return money * moneyRebate; 30 } 31 32 } 33 // 返利收费子类 34 class CashReturn : CashSuper 35 { 36 private double moneyCondition = 0.0d; 37 private double moneyReturn = 0.0d; 38 39 // 返利收费,初始化时必须要输入返利条件和返利值,比如满 300 返 100,则 moneyCondition = 300,moneyReturn = 100 40 public CashReturn(string moneyCondition, string moneyReturn) 41 42 // 43 public override double accepeCash(double money) 44 { 45 double result = money; 46 // 若大于返利条件,则需要减去返利值 47 if(money >= moneyCondition) 48 result = money - Math.Floor(money / moneyCondition) * moneyReturn; 49 50 return result; 51 } 52 } 53 // 现金收费工厂类 54 class CashFactory 55 { 56 public static CashSuper createCashAccept(string type) 57 { 58 CashSper cs = null; 59 // 根据条件返回相应的对象 60 switch(type) 61 { 62 case "正常收费": 63 cs = new CashNormal(); 64 break; 65 case "满 300 返 100": 66 CashReturn cr1 = new CashReturn("300","100"); 67 cs = cr1; 68 break; 69 case "打 8 折" 70 CashRebate cr2 = new CashRebate("0.8"); 71 cs = cr2; 72 break; 73 } 74 return cs; 75 } 76 } 77 78 // 客户端窗体部分 79 double total = 0.0d; 80 private void btnOK_Click(object sender, EventArgs e) 81 { 82 // 利用简单工厂模式根据下拉选择框,生成相应的对象 83 CashSuper csuper = CashFactory.createCashAccept(cbxType.SelectedItem.ToString()); 84 85 double totalPrices = 0d; 86 totalPrices = csuper.acceptCash(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text)); 87 88 total = total + totalPrices; 89 // 通过多态,可以得到收取费用的结果 90 lbxList.Items.Add("单价:"+ txtPrice.Text + "数量:" + txtNum.Text + "" + cbxType.SelectedItem + "合计:" + totalPrices.ToString()); 91 lbxResult.Text = total.ToString(); 92 93 }
二、策略模式

策略模式(Strategy):它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
1 // 抽象算法类,定义所有支持的算法的公共接口 2 abstract class Strategy 3 { 4 // 算法方法 5 public abstract void AlgorithmInterface(); 6 } 7 8 // ConcreteStrategy 封装了具体的算法和行为,继承于 Strategy 9 // 具体算法 A 10 class ConcreteStrategyA : Strategy 11 { 12 // 算法 A 实现方法 13 public override void AlgorithmInterface() 14 { 15 Console.WriteLine("算法 A 实现"); 16 } 17 } 18 // 具体算法 B 19 class ConcreteStrategyB : Strategy 20 { 21 // 算法 B 实现方法 22 public override void AlgorithmInterface() 23 { 24 Console.WriteLine("算法 B 实现"); 25 } 26 } 27 // 具体算法 C 28 class ConcreteStrategyC : Strategy 29 { 30 // 算法 C 实现方法 31 public override void AlgorithmInterface() 32 { 33 Console.WriteLine("算法 C 实现"); 34 } 35 } 36 37 // Context,用一个 ConcreteStrategy 来配置,维护一个对 Strategy 对象的引用。 38 // 上下文 39 class Context 40 { 41 Strategy strategy; 42 public Context(Strategy strategy) 43 { 44 this.strategy = strategy; 45 } 46 // 上下文接口 47 public void ContextInterface() 48 { 49 strategy.AlgorithmInterface(); 50 } 51 } 52 53 // 客户端代码 54 static void Main(string[] args) 55 { 56 Context context; 57 58 context = new Context(new ConcreteStrategyA()); 59 context.ContextInterface(); 60 61 context = new Context(new ConcreteStrategyB()); 62 context.ContextInterface(); 63 64 context = new Context(new ConcreteStrategyC()); 65 context.ContextInterface(); 66 67 Console.Read(); 68 }
【总结】
策略模式是一种定义一系列算法的方法,从概念上讲,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
策略模式的 Strategy 类层次为 Context 定义了一系列的可供重用的算法和行为。继承有助于析取出这些算法中的公共功能。
策略模式的另一个优点是简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
策略模式是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。
在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的 Context 对象。这本身并没有解除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由 Context 来承担,这就最大化地减轻了客户端的职责。

简单工厂模式需要让客户端认识两个类,CashSuper 和 CashFactory;而策略模式与简单工厂结合的用法,客户端就只需要认识一个类 CashContext 就可以了。耦合度更加降低。使得具体的收费算法彻底与客户端分离。
1 // 将实例化具体策略的过程由客户端转移到 Context 类中。简单工厂的应用 2 class CashContext 3 { 4 CashSuper cs = null; 5 6 public CashContext(string type) // 注意参数不是具体的收费策略对象,而是一个字符串,表示收费类型 7 { 8 switch(type) 9 { 10 case "正常收费": 11 CashNormal cs0 = new CashNormal(); 12 cs = cs0; 13 break; 14 case "满 300 返 100": 15 CashReturn cr1 = new CashReturn("300","100"); 16 cs = cr1; 17 break; 18 case "打 8 折" 19 CashRebate cr2 = new CashRebate("0.8"); 20 cs = cr2; 21 break; 22 } 23 } 24 } 25 26 // 客户端窗体部分 27 double total = 0.0d; 28 private void btnOK_Click(object sender, EventArgs e) 29 { 30 // 根据下拉选择框,将相应的算法类型字符串传入 CashContext 的对象中 31 CashContext csuper = new CashContext(cbxType.SelectedItem.ToString()); 32 33 double totalPrices = 0d; 34 totalPrices = csuper.GetResult(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text)); 35 36 total = total + totalPrices; 37 // 38 lbxList.Items.Add("单价:"+ txtPrice.Text + "数量:" + txtNum.Text + "" + cbxType.SelectedItem + "合计:" + totalPrices.ToString()); 39 lbxResult.Text = total.ToString(); 40 41 }
【参考文献】
1、《大话设计模式》

浙公网安备 33010602011771号