定义
Strategy定义了一系列的算法,并且将每个算法封装来,而且使它们还可以相互替换;策略模式让算法独立于使用它的客户而独立变化;
角色
- 环境类(Context):用一个ConcreteStrategy对象来配置,维护一个对Strategy对象的引用,可定义一个接口来让Strategy访问它的数据;
- 抽象策略类(AbstractStrategy):定义所有支持的算法的公共接口。Context使用这个接口来调用某ConcreteStrategy定义的算法;
- 具体策略类(ConcreteStrategy): 以Strategy接口实现某具体算法;
从网上找到的类图
适用场景
- 许多相关的类仅仅是行为有异,“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。即一个系统需要动态的在几种策略中选择一种;
- 需要在不同情况下使用不同的策略,或者策略还可能在未来用其他方式来实现;
- 需要对客户隐藏复杂的、与算法相关的数据结构;
- 一个类定义了多种行为,并且这些行为在这个类中以多个条件语句的形式出现;
例子
比如鸟和鸟类的行为,鸟有很多种,有会飞的,也有不会飞的,有吱吱叫的,也有呱呱叫的等等,这个时候,我们可以将鸟作为Context,也就是环境类,各种不同的鸟类作为具体的ConcreteContext,继承自鸟类,然后将鸟类的行为作为一个鸟类的接口,比如飞的行为,叫的行为,这些行为分别是Strategy,再在这些行为下面包括具体的行为,继承行为,实现行为的接口,也就是ContreteStrategy;
实现代码
var Shipping = function () {
this.company = "";
};
Shipping.prototype = {
selectExpress : function(company) {
this.company = company;
},
caculate : function(package) {
return this.company.caculate(package);
}
};
var ShunFeng = function () {
this.caculate = function (package) {
return 4.5 * package.weight;
}
};
var ShenTong = function () {
this.caculate = function (package) {
return 4.8 * package.weight;
}
};
var EMS = function () {
this.caculate = function (package) {
return 5.0 * package.weight;
}
};
var log = (function () {
var log = "";
return {
add : function(msg){
log += msg + "$
";
},
show : function(){
console.log(log);
log = "";
}
}
})();
function run()
{
var package = {weight : 40};
var sf = new ShunFeng();
var st = new ShenTong();
var ems = new EMS();
var shipping = new Shipping();
shipping.selectExpress(sf);
log.add("ShunFeng :" + shipping.caculate(package));
shipping.selectExpress(st);
log.add("ShenTong :" + shipping.caculate(package));
shipping.selectExpress(ems);
log.add("EMS :" + shipping.caculate(package));
log.show();
}
run();
其实这就是一个选择快递公司,然后计算价钱的例子;
优缺点
注意的是
- 客户必须要知道所有的策略类,并且自行决定使用哪一个策略类;
- Strategy和Context之间的通信开销;因此很可能某些 ConcreteStrategy不会都用到所有通过这个接口传递给它们的信息;简单的 ConcreteStrategy可能不使用其中的任何信息
- 策略模式会造成很多的策略类,难以管理;