策略模式介绍

介绍

策略模式(Strategy Pattern),属于行为型模式(Behavioral Patterns),指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法

eg:每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。

eg:旅行的出游方式有很多,根据去的地点,可以选择骑自行车、坐汽车或者飞机,各种出游方式都是一个策略。

优缺点

优点:  可以优化⽅法中的ifelse语句,⼤量的ifelse语句使⽤会让代码难以扩展,也不好维护,同时在后期遇到各种问题也很难维护。在使⽤策略模式后可以很好的满⾜隔离性与和扩展性,对于不断新增的需求也⾮常⽅便承接。

缺点:(1)策略类会增多。(2)所有策略类都需要对外暴露。

解决的场景

⼀般是具有同类可替代的⾏为逻辑算法场景。⽐如;不同类型的交易⽅式(信⽤卡、⽀付宝、微信)、⽣成唯⼀ID策略(UUID、DB⾃增、DB+Redis、雪花算法、Leaf算法)等,都可以使⽤策略模式进⾏⾏为包装,供给外部使⽤。

 实现

(1)定义活动的 Strategy 接口

(2)实现了 Strategy 接口的实体策略类。

(3)Context 是一个使用了某种策略的类。

 示例分析

优惠券折扣计算(优惠券类型; 1. 无门槛卷,2. 满减券,3. 折扣券)

没用策略模式

/**
 * 优惠券折扣计算接口(没用设计模式)
 * 优惠券类型; 1. 无门槛卷,2. 满减券,3. 折扣券
 *
 * @author 佛大Java程序员
 */
public class CouponDiscountService {

    /**
     * @param type        优惠劵类型
     * @param couponPrice 优惠劵金额
     * @param discount    折扣
     * @param skuPrice    商品价格
     * @param limitPrice  满足满减条件的金额
     * @return
     */
    public double discountAmount(int type, double couponPrice, double discount, double skuPrice, double limitPrice) {
        // 1. 无门槛卷
        if (1 == type) {
            return skuPrice - couponPrice;
        }

        // 2. 满减券
        if (2 == type) {
            if (skuPrice < limitPrice) {
                return skuPrice;
            }
            //如果商品价格达到满减金额limitPrice
            return skuPrice - couponPrice;
        }

        // 3. 折扣券
        if (3 == type) {
            //商品价格乘以折扣
            return skuPrice * discount;
        }

        return 0D;
    }

}

使用策略模式

策略类

/**
 * 定义活动的策略类(Strategy)接口
 * <p>
 * 优惠券折扣计算接口
 * 优惠券类型;
 * 1. 直减券
 * 2. 满减券
 * 3. 折扣券
 *
 * @author 佛大Java程序员
 */
public interface ICouponDiscountStrategy<T> {

    /**
     * 优惠券金额计算
     *
     * @param couponInfo 券折扣信息;直减、满减、折扣
     * @param skuPrice   sku金额
   * *
@return 优惠后金额 */ BigDecimal discountAmount(T couponInfo, BigDecimal skuPrice); }

实现了 Strategy 接口的实体策略类

满减卷实现类

/**
 * 实现了 Strategy 接口的实体策略类
 * 满减卷
 *
 * @author 佛大Java程序员
 */
public class MJCouponDiscount implements ICouponDiscountStrategy<Map<String, String>> {

    /**
     * 满减计算
     * 1. 判断满足x元后-n元,否则不减
     * 2. 最低支付金额1元
     */
    @Override
    public BigDecimal discountAmount(Map<String, String> couponInfo, BigDecimal skuPrice) {
        String x = couponInfo.get("x");
        String o = couponInfo.get("n");

        // 小于商品金额条件的,直接返回商品原价
        if (skuPrice.compareTo(new BigDecimal(x)) < 0) {
            return skuPrice;
        }
        // 减去优惠金额判断
        BigDecimal discountAmount = skuPrice.subtract(new BigDecimal(o));
        if (discountAmount.compareTo(BigDecimal.ZERO) < 1) {
            return BigDecimal.ONE;
        }

        return discountAmount;
    }
}

无门槛优惠劵实现类

/**
 * 实现了 Strategy 接口的实体策略类
 * 无门槛优惠劵
 *
 * @author 佛大Java程序员
 */
public class ZJCouponDiscount implements ICouponDiscountStrategy<Double> {

    /**
     * 直减计算
     * 1. 使用商品价格减去优惠价格
     * 2. 最低支付金额1元
     */
    @Override
    public BigDecimal discountAmount(Double couponInfo, BigDecimal skuPrice) {
        BigDecimal discountAmount = skuPrice.subtract(new BigDecimal(couponInfo));
        if (discountAmount.compareTo(BigDecimal.ZERO) < 1) {
            return BigDecimal.ONE;
        }

        return discountAmount;
    }

}

折扣卷实现类

/**
 * 实现了 Strategy 接口的实体策略类
 * 折扣卷实现类
 *
 * @author 佛大Java程序员
 */
public class ZKCouponDiscount implements ICouponDiscountStrategy<Double> {


    /**
     * 折扣计算
     * 1. 使用商品价格乘以折扣比例,为最后支付金额
     * 2. 保留两位小数
     * 3. 最低支付金额1元
     */
    @Override
    public BigDecimal discountAmount(Double couponInfo, BigDecimal skuPrice) {
        BigDecimal discountAmount = skuPrice.multiply(new BigDecimal(couponInfo)).setScale(2, BigDecimal.ROUND_HALF_UP);
        if (discountAmount.compareTo(BigDecimal.ZERO) < 1) {
            return BigDecimal.ONE;
        }

        return discountAmount;
    }

}

Context 是一个使用了某种策略的类

/**
 * Context 是一个使用了某种策略的类
 *
 * @author 佛大Java程序员
 */
public class CouponDiscountContext<T> {

    private ICouponDiscountStrategy<T> iCouponDiscountStrategy;

    public CouponDiscountContext(ICouponDiscountStrategy<T> couponDiscount) {
        this.iCouponDiscountStrategy = couponDiscount;
    }

    public BigDecimal discountAmount(T couponInfo, BigDecimal skuPrice) {
        return iCouponDiscountStrategy.discountAmount(couponInfo, skuPrice);
    }

}

测试类

/**
 * 测试类
 *
 * @author 佛大java程序员
 */
public class ApiTest {

    private Logger logger = LoggerFactory.getLogger(ApiTest.class);

    @org.junit.Test
    public void test_zj() {
        // 直减;100-10,商品100元
        CouponDiscountContext<Double> context = new CouponDiscountContext<>(new ZJCouponDiscount());
        BigDecimal discountAmount = context.discountAmount(10D, new BigDecimal(100));
        logger.info("测试结果:直减优惠后金额 {}", discountAmount);
    }

    @Test
    public void test_mj() {
        // 满100减10,商品100元
        CouponDiscountContext<Map<String, String>> context = new CouponDiscountContext<>(new MJCouponDiscount());
        Map<String, String> mapReq = new HashMap<String, String>();
        mapReq.put("x", "100");
        mapReq.put("n", "10");
        BigDecimal discountAmount = context.discountAmount(mapReq, new BigDecimal(100));
        logger.info("测试结果:满减优惠后金额 {}", discountAmount);
    }


    @Test
    public void test_zk() {
        // 折扣9折,商品100元
        CouponDiscountContext<Double> context = new CouponDiscountContext<>(new ZKCouponDiscount());
        BigDecimal discountAmount = context.discountAmount(0.9D, new BigDecimal(100));
        logger.info("测试结果:折扣9折后金额 {}", discountAmount);
    }

}

运行结果

 

 

 

 

 

 

 

posted @ 2020-05-05 22:52  JustJavaIt  阅读(138)  评论(0编辑  收藏  举报