您现在的位置是:首页 >其他 >【设计模式】策略模式网站首页其他

【设计模式】策略模式

boy快快长大 2024-07-12 18:01:02
简介【设计模式】策略模式

在这里插入图片描述

1.什么是策略模式

策略模式是一种行为设计模式, 它能让你定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换。

2.?

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


在这里插入图片描述
案例中我们模拟在购买商品时候使⽤的各种类型优惠券(满减、直减、折扣、n元购)
这个场景⼏乎也是⼤家的⼀个⽇常购物省钱渠道,购买商品的时候都希望找⼀些优惠券,让购买的商品更加实惠。⽽且到了⼤促的时候就会有更多的优惠券需要计算那些商品⼀起购买更加优惠!!!
这样的场景有时候⽤户⽤起来还是蛮爽的,但是最初这样功能的设定以及产品的不断迭代,对于程序员!开发还是不太容易的。因为这⾥包括了很多的规则和优惠逻辑,所以我们模拟其中的⼀个计算优惠的⽅式,使⽤策略模式来实现。

一整坨代码实现

在这里插入图片描述

package org.itstack.demo.design;

import java.math.BigDecimal;

/**
 * 优惠券折扣计算接口
 * <p>
 * 优惠券类型;
 * 1. 直减券
 * 2. 满减券
 * 3. 折扣券
 * 4. n元购
 */
public class CouponDiscountService {
    public double discountAmount(int type, double typeContent, double skuPrice, double typeExt) {
        // 1. 直减券
        if (1 == type) {
            return skuPrice - typeContent;
        }
        // 2. 满减券
        if (2 == type) {
            if (skuPrice < typeExt) {
                return skuPrice;
            }
            return skuPrice - typeContent;
        }
        // 3. 折扣券
        if (3 == type) {
            return skuPrice * typeContent;
        }
        // 4. n元购
        if (4 == type) {
            return typeContent;
        }
        return 0D;
    }
}

  • 以上是不同类型的优惠券计算折扣后的实际⾦额。
  • ⼊参包括;优惠券类型、优惠券⾦额、商品⾦额,因为有些优惠券是满多少减少多少,所以增加
    了 typeExt 类型。这也是⽅法的不好扩展性问题。
  • 最后是整个的⽅法体中对优惠券抵扣⾦额的实现,最开始可能是⼀个最简单的优惠券,后⾯随着产
    品功能的增加,不断的扩展 if 语句。实际的代码可能要⽐这个多很多。

策略模式重构代码

在这里插入图片描述

/**
 * 满减
 */
public class MJCouponDiscount implements ICouponDiscount<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;
	}
}

/**
 *
 * n元购买
 */
public class NYGCouponDiscount implements ICouponDiscount<Double> {
    /**
     * n元购购买
     * 1. 无论原价多少钱都固定金额购买
     */
    @Override
    public BigDecimal discountAmount(Double couponInfo, BigDecimal skuPrice) {
        return new BigDecimal(couponInfo);
    }
}

/**
 *
 * 直减
 */
public class ZJCouponDiscount implements ICouponDiscount<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;
    }
}
/**
 *
 * 折扣
 */
public class ZKCouponDiscount implements ICouponDiscount<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;
    }
}
public class Context<T> {
    private ICouponDiscount<T> couponDiscount;

    public Context(ICouponDiscount<T> couponDiscount) {
        this.couponDiscount = couponDiscount;
    }

    public BigDecimal discountAmount(T couponInfo, BigDecimal skuPrice) {
        return couponDiscount.discountAmount(couponInfo, skuPrice);
    }
}
/**
 * 优惠券折扣计算接口
 * <p>
 * 优惠券类型;
 * 1. 直减券
 * 2. 满减券
 * 3. 折扣券
 * 4. n元购
 */
public interface ICouponDiscount<T> {
    /**
     * 优惠券金额计算
     * @param couponInfo 券折扣信息;直减、满减、折扣、N元购
     * @param skuPrice   sku金额
     * @return           优惠后金额
     */
    BigDecimal discountAmount(T couponInfo, BigDecimal skuPrice);
}
public class ApiTest {

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

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

    @Test
    public void test_mj() {
        // 满100减10,商品100元
        Context<Map<String,String>> context = new Context<Map<String,String>>(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元
        Context<Double> context = new Context<Double>(new ZKCouponDiscount());
        BigDecimal discountAmount = context.discountAmount(0.9D, new BigDecimal(100));
        logger.info("测试结果:折扣9折后金额 {}", discountAmount);
    }

    @Test
    public void test_nyg() {
        // n元购;100-10,商品100元
        Context<Double> context = new Context<Double>(new NYGCouponDiscount());
        BigDecimal discountAmount = context.discountAmount(90D, new BigDecimal(100));
        logger.info("测试结果:n元购优惠后金额 {}", discountAmount);
    }
}

附录

1.菜鸟教程-策略模式
2.深入设计模式-策略模式

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。