大话设计模式二之策略模式

策略模式

商场收银软件

当重复代码很多,像Convert.ToDouble(),这里就写了8遍,而且4个分支要执行的语句除了打折多少以外几乎没有什么不同,应该考虑重构。
不过这还不是最主要的,如果商场的活动加大,需要有满300返100的促销算法,该怎么办?
使用简单工厂模式,可以先写一个父类,再继承它实现多个打折和返利的子类,利用多态,完成这个代码。
但是应该写几个子类?难道根据需求,比如八折、七折、五折、满300送100、满200送50,要写几个写几个?
没有必要这样,这里打折基本都是一样的,只要有个初始化参数就可以了。满几送几的,需要两个参数才行。

面向对象的编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,
具有相同属性和功能的对象的抽象集合才是类。

如果现在要增加一种商场促销手段,满100积分10点,以后积分到一定时候可以领取奖品如何做?
加一个积分算法,构造方法有两个参数:条件和返点,让它继承CashSuper,
再到收费对象生成工厂里增加100积分10点的分支条件,在到界面稍加改动就行了。
这种简单工厂模式虽然也能解决这个问题,但这个模式只是解决对象的创建问题,而且由于工厂本身包括了所有的收费方式,
商场是可能经常性地更改打折额度和返利额度,每次维护或扩展收费方式都要改动这个工厂,以致代码需要重新编译部署,
这真的是很糟糕的处理方式,所以用它不是最好的办法。面对算法的时常变动,应该有更好的办法。

策略模式:策略模式定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
商场收银系统应该考虑用策略模式。
策略模式(Strategy):它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。

商场收银时如何促销,用打折还是返利,其实都是一些算法,用工厂来生成算法对象,这没有错,但算法本身只是一种策略,
最重要的是这些算法是随时都可能互相替换的,这就是变化点,而封装变化点是我们面向对象的一种很重要的思维方式。
在客户端判断用哪一个算法。如何把这个判断的过程从客户端程序转移走呢?
简单工厂是可以转移的,现在这样子如何做到?难道简单工厂就一定要是一个单独的类码?难到不可以与策略模式的Context结合?

简单工厂模式我需要让客户端认识两个类,而策略模式与简单工厂结合的用法,客户端就只需要认识一个类CashContext就可以了。
耦合更加降低了。
在客户端实例化的是CashContext的对象,调用的是CashContext的方法GetResult,这使得具体的收费算法彻底地与客户端分离。
连算法的父类CashSuper都不让客户端认识了。


策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,
它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
对于打折、返利或者其他的算法,其实都是对实际商品收费的一种计算方式,通过继承,可以得到它们的公共功能。
公共的功能就是获得计算费用的结果GetResult,这使得算法间有了抽象的父类CashSuper.
策略模式的还有什么优点?
策略模式的Strategy类层次为Context定义了一系列的可供重用的算法或行为。继承有助于析取出这些算法中的公共功能。
策略模式的优点是简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
当不哦那个的行为对齐在一个类中时,就很难避免使用条件语句来选择合适的行为。
将这些行为封装在一个个独立的Strategy类中,可以在使用这些行为的类中消除条件语句。
策略模式封装了变化。
策略模式就是用来封装算法的,但在实践中,我们发现可以用来封装几乎任何类型的规则,只要在分享过程中听到需要
在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。
在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象。
这本身并没有解除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由Context来承担,
这就最大化地减轻了客户端的职责。

简单工厂模式与策略模式相结合已经比最初的策略模式好用了,但是在CashContext里还是用到了switch,也就是说,
如果我们需要增加一种算法,就必须要更改CashContext中的switch代码。
任何需求的变更都是需要成本的。
但是成本的高低还是有差异的。高手和菜鸟的区别就是高手可以花统一的代价获得最大的收益或者做统一的事花最小的代价。
面对同样的需求,当然是改动越小越好。这个办法就是反射技术。
反射反射,程序员的快乐。

猜你喜欢

转载自blog.csdn.net/nicolelili1/article/details/80018190