策略模式(Strategy Pattern)在外形上与状态模式很相似,但在意图上有些不同。其意图是使这些算法可以相互替换,并提供一种方法来选择最合适的算法。
在我应用OOP的设计过程演化(三)这篇文章里应用到了策略模式,在图书的租金计算上分多种情况,每一种不同类型的图书的租金是不一样的,而站在用户的角度来看,不同类型用户的租金收取又是不一样的,见下面分析:
从上面分析可知,在租金计算这块是非常复杂的,由于有这样复杂的折扣算法,使得价格计算问题需要系统地解决。
书店经营一段时间后发现生活类的图书出租量很小,或许是因为租金的原因,很少有人来租借,于是老板决定降低租金,将生活类图书的租金按照计算机类的租金价格收取。这个时候怎么办?是不是已经有现存的计算机类图书租金计算策略,此时我们只需要把生活来图书的租金计算策略换为计算机类图书的租金计算策略便OK。通过这样的分析,策略模式(Strategy)正是解决这样的问题的模式,它的定义:"准备一组算法,并将每一个算法封装起来,使得它们可以互换。"
二、模式定义
定义:"准备一组算法,并将每一个算法封装起来,使得它们可以互换。"
三、模式意图
策略模式的用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。
四、模式UML图
五、模式参与者
根据上面UML,不难看出,在策略模式里主要有三种角色:环境角色、抽象策略角色和具体策略角色。
六、简单示例
比如我们有这样一个需求,当我们的系统在记录操作日志的时候,客户要求提供多种日志记录策略,通过设置可以将日志记录到不同的地方(文本文件、XML文件以及数据库等),那么根据策略模式的定义,我们完全可以把不同的日志记录算法定义为一个独立的策略对象。
1
namespace DesignPattern.Strategy
2
}
2
1
}
1
namespace DesignPattern.Strategy
2
}
2
定义了一个抽象策略角色(Strategy),三种不同的日志记录策略(TXTStrategy、XMLStrategy和DBStrategy),也就是模式参与者中的具体策略角色,在环境角色里持有一抽象策略角色的引用,并通过构造器传入具体的策略对象初始化策略角色的引用,我们还定义了一动态设置策略的方法(SetStrategy),UML如下:
那么客户端就可以这样来使用这个策略:
1
namespace DesignPattern.Strategy
2
}
2
策略模式是一个提倡“针对接口编程”的模式,而使用接口的目的是为了统一标准或着说是制定一种强行的规定。此处抽象策略角色就担任了制定规定的角色,它制定了一种写日志(WriteLog方法)的规定。只要系统中需要记录日志就得使用这个规定(调用WriteLog方法),直接就使用他是不行的,就如去商场购物,要把商品带走不付费怎么行?
策略模式的使用是由用户发起的,根据用户的操作决定使用什么具体的策略角色。策略模式仅仅封装算法,提供新的算法加入到已有系统和算法间的相互替换,以及老算法从系统中“退休”的方便。策略模式并不决定在何时使用何种算法。因为使用何种算法决定权在用户,也就是说我们需要调用策略模式中定义好的算法方法之前,必须得选择一种具体的策略算法,上例中,客户端需要调用ContextStrategy方法,则调用前得为其设置一个具体的策略算法,如下:
1
//初始化时传入具体的策略对象
2
Context context = new Context(new XMLStrategy());
3
context.ContextStrategy();
2
3
七、PetShop 4.0中的策略模式
PetShop 4.0的体系结构非常庞大,在订单处理上设计了两种处理策略,这里也是策略模式的一个应用,IOrderStrategy接口作为订单策略的高层抽象(抽象策略角色),实现不同订单处理的具体策略去实现它,UML如下:
示意性代码:
1
namespace PetShop.IBLLStrategy
2
}
2
1
namespace PetShop.BLL
2
}
2
从上面UML和代码就可以看出,订单策略接口下有两种实现,使用了抽象工厂模式来完成相应的订单策略对象的创建 。关于定单策略对象的创建详细可查阅 定义了一系列的可供重用的算法和行为,继承有助于析取出这些算法中的公共功能。
九、参考资料
张逸 《软件设计精要与模式》
GOF 《设计模式--可复用面向对象软件的基础》
MS开源项目PetShop 4.0
注:原创文章,转载请注明出处:http://beniao.cnblogs.com 或 http://www.cnblogs.com 作者:beniao