概念定义:
当多个类的区别只在于行为,可以把行为或者算法封装成一个抽象类或者接口,类似于继承却又高于继承.官方定义是定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化.
问题描述:
继承带来的弊端,有些子类并不具备父类的行为,或者与父类行为不一致,如出现会飞的模型鸭,如果采用继承覆盖,代码量会很大,并且不利于扩展,如果采用接口,每个具体类都要写实现,不利于代码的重复利用,繁琐.
解决方案:
接口化行为类,把每个不一致的可能出现变化的行为分离出,声明为一个行为接口,如FlyBehavior,把不同Fly类型的行为生成不同的类,将行为超类声明为父类的成员变量,在之类的构造方法中指定具体的行为类.另外,父类可以添加一个方法,setFlyBehavior动态的改变子类的行为.
使用场景:
1. 以不同的格式保存文件;
2. 以不同的算法压缩文件;
3. 以不同的算法截获图象;
4. 以不同的格式输出同样数据的图形,比如曲线或框图bar等
优缺点:
优点:
1、 提供了一种替代继承的方法,而且既保持了继承的优点(代码重用)还比继承更灵活(算法独立,可以任意扩展)。
2、 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。
缺点: 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。
设计原则:
1. 找出应用中可能变化之处,把他们独立出来,不要和那些不需要改变的代码混在一起.
2. 针对接口编程,而不是针对实现编程.利用接口代表每个行为,如FlyBehavior,而不是鸭子实现Flying接口,这里就是针对FlyBehavior接口编程,而不是针对Fly来编程.
3. 多用组合,少用继承.使用组合建立系统有很大的弹性,不仅可以将算法封装,更可以在运行的时候动态的改变行为.
实例实现:
DUCK类:
public Class Duck{
FlyBehavior flyBehavior;
public Duck(FlyBehavior flyBehavior){
this. flyBehavior = flyBehavior;
};
public void flyPerform(){
flyBehavior.fly();
}
//可以动态改变飞行行为
public void set FlyBehavior(FlyBehavior fb){
this. flyBehavior = fb;
}
}
FlyBehavior接口:
public interface FlyBehavior{
public void fly();
}
FlyBehavior接口的实现:
public Class FlyWithWing implements FlyBehavior{
public void fly(){
System.out.println(“I’m flying with wing!”);
}
}
public Class FlyWithNoWay implements FlyBehavior{
public void fly(){
System.out.println(“I can’t Fly!”);
}
}
测试类:
public class Test{
public static void main(){
Duck duck = new Duck(new FlyWithWing());
duck. flyPerform();
}
}
总结:
策略模式的核心是组合,在这里是将duck类和飞行行为接口FlyBehavior组合,注入FlyBehavior的实现类.这样扩展就不需要修改现有代码.
符合依赖接口而不依赖具体类,只有在创建对象的时候指定接口的实现类,也称为依赖倒置原则,在后面工厂模式里会具体说.
Strategy和Factory有一定的类似,Strategy相对简单容易理解,并且可以在运行时刻自由切换。Factory重点是用来创建对象。 Strategy适合下列场合: 1.以不同的格式保存文件; 2.以不同的算法压缩文件; 3.以不同的算法截获图象; 4.以不同的格式输出同样数据的图形,比如曲线或框图bar等