本文共 4873 字,大约阅读时间需要 16 分钟。
模拟场景:
某某公司要求我们做一个商场收银系统,
提出需求:商场会不定时举办一系列的优惠活动,优惠方式暂定为:打折扣,满多少还多少(例如:满300还100)
初步场景分析:
看到这个需求,第一感觉就会潜意识的认为“这个太简单了”。
1.商场收银系统:定义为winform的应用程序
2.活动优惠的计算,判断一下就可以了。
初步代码实现:
好,现在我们来分析一下上面的实现:
咋一看,感觉没什么问题,可再细分析,问题就多了:
1:显示和逻辑紧密的联系在一起。
2:完全过程式的编程,没办法复用。
3:当新需求增加的时候,还需要修改这个条件分支,不符合开放封闭原则,过多的判断不利于维护。
经过以上分析,进行初步的修改:
先来看看结构图:
工厂类:
运算父类:
折扣类:
返利类:
正常收费类:
好的,经过完善之后我们的代码已经出来了,下面我们再来细细分析一下这代码:
代码使用了简单工厂模式来解决了对象的创建,通过抽象实现了业务逻辑的分离,在维护性上也得到了改善。
那么这代码就没有问题了吗?答案是:有
现在假设我们要为商场添加一种优惠活动,满100积分送10点,以后积分达到一定值就可以领取奖品。
我们该怎么去做呢:现在有了工厂,我们只需要添加一个积分的类,
让它继承运算父类(CashSuper),在再工厂条件分支里添加一个满100积分送10点的条件分支,界面再稍稍修改就可以了。
这么想虽然是可以解决问题,但是工厂里包含了所有的收费方式,商场是可能经常性的更改打折额度,添加新的优惠方式,
如果是这样的话,我们每次维护或扩展收费方式都要去改动这个工厂,这样做就不得不让代码重新编译部署,这样的处理方式是很糟糕的。
那么我们该如何去做呢?现在我们就进入正题:其实商场的促销活动,打折活动,返利活动都是一些算法,而算法本身只是一种策略,
最重要的是这些算法是随时都可能互相替换的,这就是变化点,而封装变化点是我们面向对象的一种很重要的思维方式。
我们先来看看策略模式的结构图:
Strategy类,定义所有支持的算法和公共接口:
ConcreteStrategy封装了具体的算法或行为,继承于Strategy:
Context,用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用:
客户端的实现:
下面我们就用策略模式来改善一下我们的代码:
代码结构图:
现有的代码没有CashContext,我们就添加一个CashContext的类:
其他的类不变,客户端实现:
经过策略模式完善的代码已经实现,下面我们再来分析一下我们的代码:
现在问题又来了,算法的判断又回到客户端里来了,我们该如何去解决这个问题呢?
其实我们可以让策略模式与简单工厂模式相结合,下面我们来看看怎么个实现法:
在CashContext里进行对象的构造:
客户端实现:
经过进一步的优化,我们的代码已经比较的优化了,但是一个很明显的问题也显示出来了,就是switch的条件判断分支,
当我们需要添加一种算法的时候,我们还是需要修改CashContext里的switch算法,这样的代码还是让人非常的不爽,哪还有什么方法呢?
我们可以使用反射来改善现有的代码(反射的具体原理与实现将在不久写出):
switch算法的条件判断分支我们抽取出来,用一个xml文件进行记录:
接下来我们只需要在加载事件中将xml的信息读取出来绑定就可以了:
由于我们的switch已经转移到xml中了,那么我们的CashContext类就可以简化成:
我们的具体算法实现类不变,现在我们最主要就是通过反射去实例化不同的算法对象:
总结:
代码经过多次的修改,可维护性,代耦合高内聚的特性已经展现出来了,现在我们再来分析一下上面的代码吧,上面我们通过反射去除了switch分支,
有效的把耦合降到最低,但是这样做也是有一点点代价的,反射会比较耗一点性能,所以我们做程序的时候要具体问题具体分析。
通过上面的代码我们来分析一下策略模式吧:
策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
优点:
1、策略模式简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试,每个算法可以保证它没有错误,修改其中任一个时也不会影响其他的算法。
2、策略模式封装了变化,策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则, 只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。
3、策略模式有利于程序的高内聚、低偶合性,使得程序更加的灵活。
缺点:
基本策略模式中所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象, 这本身并没有解除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由Context来承担,这就是最大化地减轻了客户端的职责。
转自:http://blog.csdn.net/shiyuan17/article/details/9056637