一、定义


  策略(strategy)模式属于对象的行为模式。其用途是针对一组算法,将每个不同算法封装到具有共同接口的独立类中,从而使他们可以相互替换。即使 算法和对象分开来,使得算法可以独立于使用它的客户而变化。

二、场景


某个市场人员接到单后的报价策略。报价策略很复杂,可以简单作如下分类:

  • 普通客户小批量,不打折
  • 普通客户大 批量,打9折
  • 老 客户小批量,打8.5折
  • 老 客户大批量,打8折
    我们通常可以适用条件语句进行处理,代码如下:
public class Test {
    public double getPrice(String type ,double price ){
        if(type.equals("普通客户小批量")){
            System.out.println("不打折");
            return price;
        }else if(type.equals("普通客户大批量")){
            System.out.println("打9折");
            return price*0.9;

        }else if(type.equals("老客户小批量")){
            System.out.println("打8.5折");
            return price*0.85;

        }else if(type.equals("老客户大批量")){
            System.out.println("打8折");
            return price*0.8;
        }
        return price;
    }
}

这样实现起来比较简单,符合一般开人员的思路,但是当类型特别多,算法比较复杂时,整个条件控制代码会变得很长,难于维护。这时我们可以采用策略模式,将不同的策略分开,委派给不同的对象管理。

三、模式结构


结构图:

java 策略设计模式实战 java实现策略模式_客户端

  • Context环境角色 : 持有一个Strategy的引用。
  • Strategy抽象策略角色: 这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
  • ConcreteStrategy具体策略角色: 包装了相关的算法或行为。

示例代码:

Strategy抽象策略角色:

public interface Strategy {
    /**
     * 
     * @param price 商品原价
     * @return 打折后价格
     */
    public double getPrice(double price);
}

ConcreteStrategy具体策略角色:

public class NewCustomerFewStrategy implements Strategy{

    public double getPrice(double price) {
        System.out.println("普通客户小批量,不打折");
        return price;
    }
}



public class NewCustomerManyStrategy implements Strategy{

    public double getPrice(double price) {
        System.out.println("普通客户大批量,打9折");
        return price*0.9;
    }
}



public class OldCustomerFewStrategy implements Strategy{

    public double getPrice(double price) {
        System.out.println("老客户小批量,打8.5折");
        return price*0.85;
    }
}




public class OldCustomerManyStrategy implements Strategy{

    public double getPrice(double price) {
        System.out.println("老客户大批量,打8折");
        return price;
    }
}

Context环境角色:

public class Context {
    private Strategy strategy;//持有策略引用

    public Context(Strategy strategy) {
        super();
        this.strategy = strategy;
    }
    public void printPrice(double price ){
        System.out.println("价格为:"+strategy.getPrice(price));
    }
}

客户端:

public class Client {
     public static void main(String[] args) {
        Strategy strategy= new NewCustomerFewStrategy();
        Context context= new Context(strategy);
        context.printPrice(100);
    }

}  

//输出结果
普通客户小批量,不打折
价格为:100.0

从上面的示例可以看出,策略模式仅仅封装算法,提供新的算法插入到已有系统中,以及老算法从系统中“退休”的方法,策略模式并不决定在何时使用何种算法。在什么情况下使用什么算法是由客户端决定的。

四、总结


优点

  • 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复。
  • 使用策略模式可以避免使用多重条件(if-else)语句。多重条件语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重条件语句里面,比使用继承的办法还要原始和落后。

缺点:

  • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。
  • 由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。