首先解释下,我每次贴出来的代码。都是只给出主要部分的代码。便于大家理解,有人说运行不了的。请谅解哈。
上次我们简单的介绍了简单工厂模式,我们知道,只要有统一归类的操作,我们就可以抽象出一个父类出来,然后根据不同的条件来用工厂模式实例化不同的对象,然后用父类的姿态显示出来。但是相对于我们面向对象的编程思想来说。这种简单工厂模式还是有一定的缺点的,一旦我们需要再添加新的操作,就需要再定义一个新的子类并且继承同一个父类,而且需要修改工厂类中的代码,因为我们要添加新的子类和判断条件(比如我需要给计算器增加一个开平方的功能),在Operation类还需要增加相应的判断条件。很明显,这种模式的有着高耦合,一旦我们需要改变需求,就需要大量修改修改原本已经写好的代码,在需求的不断变化过程中,这不是一件很好的事。
现在呢。在我们面前会再有一个案例。一个商场打算做一种促销,促销方式有两种。
1.购物满500返200.
2.超过200元打8折。
然后计算出客户购买商品之后应付的金额。
这样的需求在不变得情况下是很容易写出来的。但是,如果我需要把打折的数字和返现的数字是需要变化的呢?或者我们需要再添加一种新的打折方式呢?
虽然简单工厂模式可以实现这个功能,但是商场的这种促销模式是不断的改变的,所以简单工厂的代码就需要不断的修改,程序就需要不断的再次编译和生产。那么好的方法是什么呢?
面对算法的经常变动,策略模式就应运而生。
面向对象的编程,并不是类越多就越好,类的划分是为了封装,但是分类的基础和原则是抽象,具有相同属性和功能的对象的抽象集合才是类。
策略模式定义了算法家族,分别封装起来,让他们之间可以互相替换,该模式让算法的变化,不会影响到使用算法的客户。
首先。定义算法抽象类,算法抽象类中有个算法实现的抽象方法,各种算法继承算法抽象类,然后重写算法抽象方法
其次,定义Context类。Context为上下文类,在该类中先声明一个抽象类的对象,然后按照客户所选的条件实例化具体的算法对象。然后再在该类中写一个方法,这个方法中其实是调用了抽象类的方法,用来显示算法对象的功能。
最后我们只需要定义不同的算法来继承算法抽象类即可。
下面给大家看看策略模式的图解:
关于上面我们解释的策略模式,我们就用收银这个案例来实现下。代码虽然是我敲到博客中来的,但是该案例出自大话设计模式中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98 |
namespace
收银台 { /// <summary> /// 现金收费抽象类 /// </summary> abstract
class
CashSuper { public
abstract
double
acceptCash( double
money); } /// <summary> /// 正常收费继承CashSuper /// </summary> class
CashNormal : CashSuper { public
override
double
acceptCash( double
money) { return
money; } } /// <summary> /// 打折收费类 /// </summary> class
CashRebate : CashSuper { private
double
moneyRebate = 1d; public
CashRebate( string
moneyRebate) { //在构造方法中对打折进行赋值 this .moneyRebate = double .Parse(moneyRebate); } public
override
double
acceptCash( double
money) { return
money*moneyRebate; } } /// <summary> /// 现金返利类 /// </summary> class
CashReturn : CashSuper { private
double
moneyCondition = 0.0d; //返利起点 private
double
moneyReturn = 0.0d; //返利金额 public
CashReturn( string
moneyCondition, string
moneyReturn) { //对返利起点,和返利金额初始化 this .moneyCondition = double .Parse(moneyCondition); this .moneyReturn = double .Parse(moneyReturn); } public
override
double
acceptCash( double
money) { double
result=money; if
(money > moneyCondition) result = money - Math.Floor(money / moneyCondition) * moneyReturn; //超过返利起点的部分全部都参加返利? return
result; } } /// <summary> /// 现金收费工厂类 /// 有了策略模式 就不在需要这个简单工厂来产生需要的对象。 /// </summary> class
CashFactory { public
static
CashSuper CreatCashAccept( string
type) { CashSuper cs = null ; switch
(type) { case
"正常收费" : cs= new
CashNormal(); break ; case
"满300反100" : cs = new
CashReturn( "300" , "100" ); break ; case
"打8折" : cs = new
CashRebate( "0.8" ); break ; } return
cs; } } /// <summary> /// 上下文类 /// </summary> class
Context { private
CashSuper cs= null ; public
Context( string
type) { //修改了Context 把实例化子类 直接放在了上下文的构造方法中 //参数是有UI界面得来的 彻底分离了UI与逻辑。 switch
(type) { case
"正常收费" : cs = new
CashNormal(); break ; case
"满300反100" : cs = new
CashReturn( "300" , "100" ); break ; case
"打8折" : cs = new
CashRebate( "0.8" ); break ; } } public
double
Getresult( double
money) { return
cs.acceptCash(money); } } } |
然后,我们再给出客户端的主要代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 |
private
void
btnok_Click( object
sender, EventArgs e) { /*在这里使用策略模式 一样是创建上下文类来控制到底使用哪种算法 需要用上下文类来实现算法的选择以及把实例化的子类赋值给 * 上下文中的父类。 * 再用上下文类中的方法来调用父类的从子类中获得到的方法。 */ Context ct = new
Context(cmb1.SelectedItem.ToString()); double
totalPrice = 0d; totalPrice = ct.Getresult(Convert.ToDouble(txtboxprice.Text) * Convert.ToDouble(txtboxnumber.Text)); //计算每个商品的总价 total = total + totalPrice; listBox1.Items.Add( "单价:"
+ txtboxprice.Text + "数量"
+ txtboxnumber.Text + " "
+ cmb1.SelectedText + "合计"
+ totalPrice.ToString()); labCount.Text = total.ToString(); } |
我们从客户端的代码中不难发现,我们把进行判断的事情都放在了上下文Context类中。这个类不但维护了判断条件,而且所有算法对象的实现都是在这个类中产生。一旦需要修改,我们需要做的就是添加算法类继承抽象算法,和在Context类中增加对该算法的判断即可。
虽然这个策略模式在需求变化的同时,并没有完全的解耦,还是需要修改程序代码,但是相比简单工厂的需要修改两处,这里需要修改一处。是不是已经好了很多呢?
我们拿出来计算器-简单工厂的客户端代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 |
class
Program { static
void
Main( string [] args) { Console.WriteLine( "请输入第一个数:" ); int
num1 = int .Parse(Console.ReadLine()); Console.WriteLine( "请输入第二个数:" ); int
num2 = int .Parse(Console.ReadLine()); Console.WriteLine( "请输入运算符:" ); string
mark = Console.ReadLine(); Operation opc = FactoryClass.Panduan(mark); if
(opc != null ) { Console.WriteLine(opc.Run(num1, num2)); } else { Console.WriteLine( "无效的运算符!" ); } Console.ReadKey(); } } |
在这里,我们的客户端需要认识两个类才能完成计算的操作,Operation,和Factory。
但是我们回头看看策略模式,我们的客户端只需要认识一个Context上下文类,就能完全实现这些功能,耦合度也就随之降低了。
策略模式和简单工厂的配合使用
策略模式是一种定义一系列算法的方法,从概念上看,所有的这些算法完成的都是相同的工作,只是实现不同,他可以以相同的方式调用所有的算法,减少了各类算法与算法类之间的耦合性。策略模式也简化了单元测试,每个算法都有自己的类,可以通过直接的接口进行单独的测试。策略模式就是用来封装算法的,但是在实践中,几乎所有的类型规则,只要在分析过程中,听到在
不同的时间应用不同的业务规则。就可以考虑使用策略模式处理这种变化的可能性。
原文:http://www.cnblogs.com/ruhuaxiao/p/3614497.html