• 策略模式介绍


    介绍

    策略模式(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);
        }
    
    }

    运行结果

     

    希望本文章对您有帮助,您的转发、点赞是我的创作动力,十分感谢。更多好文推荐,请关注我的微信公众号--JustJavaIt
  • 相关阅读:
    梦幻如初,心不忘。
    整数集和求并
    ACTF 2014 Write up
    适用web的图片
    jqGrid
    angularjs
    【转载】FPGA异步时钟设计中的同步策略
    Cordic的学习之硬件实现
    Cordic的学习初步
    DDS---三角函数发生器的用法
  • 原文地址:https://www.cnblogs.com/liaowenhui/p/14089272.html
Copyright © 2020-2023  润新知