设计模式--策略模式

212 阅读3分钟

什么是策略模式

在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
其思想是针对一组算法,将每一种算法都封装到具有共同接口的独立的类中,从而是它们可以相互替换。策略模式的最大特点是使得算法可以在不影响客户端的情况下发生变化,从而改变不同的功能。

简单解释

参照大话设计模、菜鸟教程。1、商场收费为例,无论原价收取、打折收取还是满300减50,这些都是一个一个的策略。2、外出旅行,无论选择坐巴士、骑自行车或选择飞机出生,这都是一个一个的策略。这些策略都是随时可能互相替换,且互相之前并不影响。

  • 优点
    1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。
  • 缺点
    1、策略类会增多。 2、所有策略类都需要对外暴露。

代码解释

参照大话设计模式中的商场促销,商场促销分别是打折、满减或者原价收费,我们可以把计算收费做为抽象方法提取出来;
1、定义抽象类,将计算费用方法抽象;

/**
 * 抽象算法类,定义算法
 */
public abstract class Strategy {

    /**
     * 算法方法
     */
    public abstract Double getMoney(Double money);
}

2、分别定义子类,正常收费、打折收费、满减收费三个子类,继承抽象类,实现具体方法

/**
 * 正常收费
 */
public class StrategyNormal extends Strategy {

    @Override
    public Double getMoney(Double money) {
        System.out.println("正常收费");
        return money;
    }
}
/**
 * 打折收费
 */
public class StrategyRebate extends Strategy {

    private Double rebate;

    /**
     * 实例化时,传入具体打折参数,例:打八折,则传入0.8
     * @param rebate
     */
    public StrategyRebate(Double rebate){
        this.rebate=rebate;
    }

    @Override
    public Double getMoney(Double money) {
        return money*rebate;
    }
}
/**
 * 满减收费 满300减100
 */
public class StrategyReturn extends Strategy {

    private Double moneyCondition;
    private Double moneyReturn;

    /**
     * 传满足条件后,减多少费用
     * @param moneyCondition 条件
     * @param moneyReturn 减免条件
     */
    public StrategyReturn(Double moneyCondition,Double moneyReturn){
        this.moneyCondition=moneyCondition;
        this.moneyReturn=moneyReturn;
    }

    @Override
    public Double getMoney(Double money) {
        if(money>=this.moneyCondition){
            return money-this.moneyReturn;
        }
        return money;
    }
}

3、定义一个配置类,维护针对于算法的引用

/**
 * 针对于算法的引用,根据具体的策略对象调用其算法方法
 */
public class StrateContext {

    private Strategy strategy;

    public StrateContext(Strategy strategy){
        this.strategy=strategy;
    }

    public Double getMoney(Double money){
        return strategy.getMoney(money);
    }
    /**
     * 示例
     * @param args
     */
    public static void main(String[] args) {
        //正常收费
        StrateContext context=new StrateContext(new StrategyNormal());
        Double d1=context.getMoney(100.0d);
        System.out.println("正常收费:"+d1);

        //满300减100
        StrateContext context1=new StrateContext(new StrategyReturn(300d,100d));
        Double d2=context1.getMoney(350d);
        System.out.println("满300减100:"+d2);

        //打八折
        StrateContext context2=new StrateContext(new StrategyRebate(0.8d));
        Double d3=context2.getMoney(100d);
        System.out.println("打八折:"+d3);
    }
}

后记

以上代码仅仅实现了策略模式的简单使用,通常业务代码中可能还要更复杂,但是万变不离其中,通过将策略模式与工厂模式接合,将可以实现代码应用的松藕合;

与工厂模式接合

获取每一个策略都需要进行客户端的判断,代码耦合太紧,同时不利于后期维护,仅仅这样处理那么与采取策略模式的初衷不符;
1、创建一个工厂类,用于实例化计算类

public class StrateContextFac {

    private Strategy strategy;

    public StrateContextFac(String type){
        switch (type){
            case "正常收费":
                strategy=new StrategyNormal();
                break;
            case "满300减100":
                strategy=new StrategyReturn(300d,100d);
                break;
            case "打八折":
                strategy=new StrategyRebate(0.8d);
                break;
        }
    }
    public Double getMoney(double money){
        return strategy.getMoney(money);
    }

}

2、调用计算

public static void contextFac(){
        String type="打八折";
        StrateContextFac fac=new StrateContextFac(type);
        Double money=fac.getMoney(100d);
        System.out.println(type+":"+money);
    }

与工厂模式接合后,只需要关心传入的类型与数据,而不需要去维护相关的计算类,计算类由工厂直接调用并生成;