设计模式之策略模式

概念

​ 定义一族算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端(这里的客户端代指使用算法的代码)。

一提到策略模式,有人就觉得,它的作用是避免 if-else 分支判断逻辑。实际上,这种认识是很片面的。策略模式主要的作用还是解耦策略的定义、创建和使用,控制代码的复杂度,让每个部分都不至于过于复杂、代码量过多。除此之外,对于复杂代码来说,策略模式还能让其满足开闭原则,添加新策略的时候,最小化、集中化代码改动,减少引入 bug 的风险。

关键点:定义、创建、使用

  • 定义策略接口,算法,一组实现该接口的策略类;
  • 策略的创建由工厂来完成,封装创建策略的细节;
  • 策略选择使用有两种方式:
  • 一种是静态确定,直接new 相应的策略接口;
  • 一种是动态确定,根据运行参数动态实例化策略接口;

策略定义

1. 定义策略接口

/**
 * 策略接口
 */
public interface Strategy {

    /**
     * 优惠算法
 	*/
    Object discount();
}

2. 定义一组实现接口的策略类

  • 打折策略类
public class DiscountStrategy implements Strategy {

    @Override
    public Object discount() {
        System.out.println("打折");
        return null;
    }
}
  • 减价策略类
public class ReducePriceStrategy implements Strategy {

    @Override
    public Object discount() {
        System.out.println("减价");
        return null;
    }
}
  • 赠送优惠券策略类
public class FreeProductStrategy implements Strategy {

    @Override
    public Object discount() {
        System.out.println("赠送产品");
        return null;
    }
}

策略工厂

1. 策略枚举类型

public enum DiscountEnum {
    DISCOUNT,   /** 打折 **/
    REDUCE_PRICE,     /** 减价 **/
    FREE_COUPON, /** 赠送优惠券 **/
    FREE_PRODUCT; /** 赠送产品 **/
}

2. 策略工厂

2.1 无状态的策略工厂

当具体的优惠算法中是无状态的,那么可以用map将类型和策略相对应,在获取具体实现策略时通过 “查表法” 即可获取到相应的策略实现。

/**
 * 无状态的策略工厂
 * 无状态指的是纯算法,不需要每次调用都创建一个新的Strategy
 */
public class StrategyFactory {

    private static final Map<DiscountEnum,Strategy> strategies = new HashMap<>();

    static {
        strategies.put(DiscountEnum.DISCOUNT,new DiscountStrategy());
        strategies.put(DiscountEnum.REDUCE_PRICE,new ReducePriceStrategy());
        strategies.put(DiscountEnum.FREE_COUPON,new FreeCouponStrategy());
        strategies.put(DiscountEnum.FREE_PRODUCT,new FreeProductStrategy());
    }

    /**
     * 获取具体的实现策略
     * @param discountEnum
     * @return
     */
    public static Strategy getStrategy(DiscountEnum discountEnum) {
        if(discountEnum == null) {
            throw new IllegalArgumentException("discountNum should not be null");
        }
        return strategies.get(discountEnum);
    }
}

2.2 有状态的策略工厂

当策略算法是有状态的,那么就需要在每次获取策略时重新创建策略类。可以通过反射的方式动态实例化出对象,使用map存储类型与策略Class的关系、或者通过注解动态创建。

这里使用map存储,一样通过map查表法创建;

/**
 * 有状态的策略工厂
 */
public class StrategyFactory2 {

    private static final Map<DiscountEnum,Class<? extends Strategy>> strategies = new HashMap<>();

    static {
        strategies.put(DiscountEnum.DISCOUNT, DiscountStrategy.class);
        strategies.put(DiscountEnum.REDUCE_PRICE, ReducePriceStrategy.class);
        strategies.put(DiscountEnum.FREE_COUPON, FreeCouponStrategy.class);
        strategies.put(DiscountEnum.FREE_PRODUCT, FreeProductStrategy.class);
    }

    /**
     * 每一次获取都重新创建一个 Strategy
     */
    public static Strategy getStrategy(DiscountEnum discountEnum) throws InstantiationException, IllegalAccessException {
        if(discountEnum == null) {
            throw new IllegalArgumentException("discountNum should not be null");
        }

        Class<? extends Strategy> strategyClass = strategies.get(discountEnum);
        return strategyClass.newInstance();
    }

}

策略的使用

  • 运行时动态创建
 /**
     * 运行时动态确定
     */
    @Test
    public void testStrategy() {
        // 假设动态运行时获取的类型为减价类型
        DiscountEnum discountEnum = DiscountEnum.REDUCE_PRICE;
        Strategy strategy = StrategyFactory.getStrategy(discountEnum);
        strategy.discount();
    }
  • 静态创建
/***
     * 静态确定策略
     */
    @Test
    public void testStrategy4Static() {
        // 假设知道要使用的算法为减价,直接new对应的策略实例
        Strategy strategy = new DiscountStrategy();
        strategy.discount();
    }

总结

从上面的过程中可以发现,策略模式实际上就是定义算法接口 + 工厂模式的组合,通过定义算法接口规定算法签名,利用查表法在策略集合中找到符合条件的策略,从而实现不同策略的切换。从表现上看是抽离了if-else 的逻辑,实际上更多的作用是解耦了策略的定义、创建以及使用,使每个部分不至于过于复杂,从而最小化、集中化的管理代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值