1.介绍:
1)策略模式(Strategy Pattern)中,定义算法族(策略组),分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。比如下文中出现的野鸭是使用算法的客服,实现会飞接口的类组是算法组,在野鸭类中可以使用、替换算法组中某个类。
2)这个算法体现了几个设计原则,第一把变化的代码从不变的代码中分离出来;第二针对接口编程而不是具体类(定义了策略接口);第三多用组合/聚合,少用继承(客服通过组合方式使用策略)
2.原理类图
3.策略模式的注意事项和细节
策略模式的关键是:分析项目中变化部分与不变部分
策略模式的核心思想是:多用组合/聚合 少用继承;用行为类组合,而不是行为的继承。更有弹性。
体现了“对修改关闭,对拓展开放”原则,客服端增加行为不用修改原有代码,只要添加一种策略模式(或者行为)即可,避免了使用多重转移语句(if…else if …else)
需要注意的是:每添加一个策略就要增加一个类,当策略过多是会导致类数目庞大的
4.代码的实现
当使用继承的时候的时候:会出现的问题
鸭子类的父类
public abstract class Duck {
//鸭子的信息描述
public abstract void display();
public void quack(){
System.out.println("鸭子嘎嘎叫~~~");
}
public void swim(){
System.out.println("鸭子会游泳~~~");
}
/**
* 因为并不是所有的鸭子都会飞,这样继承了这个鸭子类的子类就要重写了这个方法
*/
public void fly(){
System.out.println("鸭子会飞~~~");
}
}
野鸭
public class WildDuck extends Duck{
@Override
public void display() {
System.out.println("这个一个野鸭");
}
}
北京鸭
public class PekingDuck extends Duck{
@Override
public void display() {
System.out.println("这个一个北京鸭");
}
@Override
public void fly() {
System.out.println("飞行的很糟糕");
}
}
玩具鸭,因为玩具鸭不会飞,但是也继承了父类方法,所以需要重写
public class ToyDuck extends Duck{
@Override
public void display() {
System.out.println("这个一个玩具鸭");
}
/**
* 因为玩具鸭不会飞所以需要重写
*/
@Override
public void fly() {
System.out.println("玩具鸭不会飞");
}
}
从上面的代码中可以看出来,如果是通过继承来写,则不要父类中的方法时候,就显得多余了。加上如果需要额外加上鸭子吃的食物是什么的时候,这样又要修改父类里面的方法,每个子类的方法也要修改了。
如果是用策略模式是怎样的呢:
fly的策略接口
/**
* 鸭子飞行为的接口,算法组的接口
*/
public interface FlyInf {
public void fly();
}
fly实现类接口,fly的各种表现
//飞行好的行为
public class GoodFly implements FlyInf {
@Override
public void fly() {
System.out.println("飞行的很棒");
}
}
//飞行一般的行为
public class BadFly implements FlyInf {
@Override
public void fly() {
System.out.println("飞行的很糟糕");
}
}
//不会飞行的行为
public class NoFly implements FlyInf {
@Override
public void fly() {
System.out.println("不能飞行");
}
}
将策略接口组合到使用者的身上
修改后的duck类
public abstract class Duck {
FlyInf flyInf;
//鸭子的信息描述
public abstract void display();
public void quack(){
System.out.println("鸭子嘎嘎叫~~~");
}
public void swim(){
System.out.println("鸭子会游泳~~~");
}
/**
* 通过接口调用方法
*/
public void fly(){
if (this.flyInf != null) {
flyInf.fly();
}
}
/**
* 修改策略
* @param flyInf
*/
public void setFlyInf(FlyInf flyInf) {
this.flyInf = flyInf;
}
}
修改后的野鸭类
public class WildDuck extends Duck{
//将策略组合到使用者上
public WildDuck(){
this.flyInf = new GoodFly();
}
@Override
public void display() {
System.out.println("这个一个野鸭");
}
}
修改后的北京鸭类
public class PekingDuck extends Duck{
public PekingDuck(){
this.flyInf = new BadFly();
}
@Override
public void display() {
System.out.println("这个一个北京鸭");
}
}
修改后的玩具鸭类
public class ToyDuck extends Duck{
public ToyDuck(){
this.flyInf = new NoFly();
}
@Override
public void display() {
System.out.println("这个一个玩具鸭");
}
}
主类
public class TestStrategy {
public static void main(String[] args) {
WildDuck wildDuck = new WildDuck();
wildDuck.fly();
PekingDuck pekingDuck = new PekingDuck();
pekingDuck.fly();
ToyDuck toyDuck = new ToyDuck();
toyDuck.fly();
//改变了策略中的某个飞行行为
toyDuck.setFlyInf(new GoodFly());
System.out.println("玩具鸭被装上了翅膀可以飞了");
toyDuck.fly();
}
}
输出
策略模式在JDK中的使用:
public class TestStrategy2 {
public static void main(String[] args) {
Integer[] a = {1,8,2,3,7,6};
//comparator是一个策略接口,实现自定义的策略
Comparator comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
if (o1 > o2){
return 1;
}else {
return -1;
}
}
};
Arrays.sort(a, comparator);
System.out.println(Arrays.toString(a));
}
}
总结:策略模式,是将行为独立成为模块,需要的时候去拿自己对应行为的实现类就可以了。