设计模式(一)简单工厂与策略模式

设计模式用 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 }
View Code

一、简单工厂模式

代码实现

 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();
OperationFactory

 

代码结构图

 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

 【总结】

策略模式是一种定义一系列算法的方法,从概念上讲,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。

策略模式的 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 }
CashContext

 

 

【参考文献】

1、《大话设计模式》

 

posted @ 2015-06-16 10:43  壬子木  阅读(198)  评论(0)    收藏  举报