如何写好一个策略模式

首先我们要知道策略模式的使用场景

  1. 购物车优惠
  2. 排序算法
  3. 游戏AI决策
  4. .......等等

我认为策略模式就是对开闭原则的一种很好的体现.对添加开放,对修改,删除关闭,使系统更加灵活,易于扩展和维护

最常用的就是营销策略,所以示例是做的一个营销策略的策略接口

首先我们先创建一个接口,里面需要有三个方法

  1. 判断优惠规则,返回一个布尔类型
  2. 如果第一个方法判断为true,那么将这个策略规则返回
  3. 策略规则的名称(可以不用,根据业务需求定)

 

然后去实现这个借口,一个实现类就是一种优惠方案

 

 

做完这些我们的策略接口就写好了,然后再去实现怎么调用它

我们需要创建一个类,里面将所有的策略方案创建出来放入一个集合中

(这里使用到了单例模式和工厂模式)

然后我们写一个方法,带着传过来的优惠券编号去数据库查找优惠券的信息(我的数据库是有一个字段记录的优惠券类型 1-满100-20  2-满100打五折)

这样我们就可以通过我们自己封装的isScheme()方法匹配优惠规则

 

到这里,策略模式和匹配方法就都实现了,最后只用调用一下匹配方法,将价格优惠券编号和订单号等信息就可以直接得到折后的价格了



接下来就是代码环节

controller层

package com.dragon.discount.controller;

import com.dragon.common.core.domain.Result;
import com.dragon.discount.service.DiscountService;
import com.dragon.discount.common.domain.DTODiscounted;
import com.dragon.discount.common.domain.VODiscounted;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author FangShiBa
 * @date 2024/3/3
 * @apiNote
 */
@RestController
@RequestMapping("/discount")
public class DiscountController {
    @Autowired
    private DiscountService discountService;


    /**
     * 营销模式策略接口
     * @param voDiscounted
     *     private  Integer orderId;           //订单编号
     *     private BigDecimal originalPrice;   //原总价
     *     private List<DiscountProduct> products;     //商品信息
     *     private Integer couponsId;          //优惠券编号
     * @return
     */
    @PostMapping("/getDiscountPrice")
    public Result<DTODiscounted> getDiscountPrice(@RequestBody VODiscounted voDiscounted){
        return discountService.getDiscountPrice(voDiscounted);
    }

}

service

package com.dragon.discount.service;

import com.dragon.common.core.domain.Result;
import com.dragon.discount.common.domain.DTODiscounted;
import com.dragon.discount.common.domain.VODiscounted;

/**
 * @author FangShiBa
 * @date 2024/3/3
 * @apiNote
 */
public interface DiscountService {
    Result<DTODiscounted> getDiscountPrice(VODiscounted voDiscounted);


}

serive实现类

package com.dragon.discount.service.impl;

import com.dragon.common.core.domain.Result;
import com.dragon.discount.service.DiscountService;
import com.dragon.discount.service.ITCouponsTypeService;
import com.dragon.discount.strategy.Discounts;
import com.dragon.discount.common.domain.DTODiscounted;
import com.dragon.discount.common.domain.VODiscounted;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author FangShiBa
 * @date 2024/3/3
 * @apiNote
 */
@Service
public class DiscountServiceImpl implements DiscountService {
    @Autowired
    private DisCountFactory disCountFactory;
    @Override
    public Result<DTODiscounted> getDiscountPrice(VODiscounted voDiscounted) {
        Discounts discounts = disCountFactory.getDiscounts(voDiscounted);
        Result<DTODiscounted> audit = discounts.audit(voDiscounted);
        return audit;
    }
}

营销方案的工厂

package com.dragon.discount.service.impl;

import com.dragon.discount.common.domain.TCouponsType;
import com.dragon.discount.service.ITCouponsTypeService;
import com.dragon.discount.strategy.Discounts;
import com.dragon.discount.strategy.impl.Discount1;
import com.dragon.discount.common.domain.VODiscounted;
import com.dragon.discount.strategy.impl.Discount2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * @author FangShiBa
 * @date 2024/3/3
 * @apiNote
 */
@Component
public class DisCountFactory {
    @Autowired
    private ITCouponsTypeService itCouponsTypeService;
    //在程序运行时就将所有策略方案放入集合中
    private final static DisCountFactory factory=new DisCountFactory();
    private static DisCountFactory getInstance(){
        return factory;
    }
    private List<Discounts> discountsList = new ArrayList<>();

    private DisCountFactory(){
        //将所有优惠方案放入集合(PS:这里其实并不完全满足开闭原则,如果添加新的优惠策略还是需要修改这里的代码,有更优的解决方案)
        discountsList.add(new Discount1());
        discountsList.add(new Discount2());

    }

    public Discounts getDiscounts(VODiscounted voDiscounted){
        //查询使用的优惠券信息
        TCouponsType couponsType = itCouponsTypeService.selectTCouponsTypeByCouponsTypeId(voDiscounted.getCouponsId().longValue());
        //创建一个空的策略方案,用来接收匹配的方案
        Discounts discounts=null;
        //遍历所有优惠方案
        for (Discounts discounts1 : discountsList) {
            //判断策略方案是否匹配(自己封装的方法)
            if(discounts1.isScheme(couponsType.getJudgment().intValue())){
                if(discounts==null){
                    //如果与判断逻辑相符,则将优惠规则放入策略方案
                    discounts=discounts1;
                }
            }
            //这里还要对不在我们优惠方案以内的值进行处理(比如我只有1-2两种优惠方案,但是传了一个3进来)
        }
        //将策略方案返回
        return discounts;
    }


}

策略接口

package com.dragon.discount.strategy;

import com.dragon.common.core.domain.Result;
import com.dragon.discount.common.domain.DTODiscounted;
import com.dragon.discount.common.domain.VODiscounted;

/**
 * @author FangShiBa
 * @date 2024/3/3
 * @apiNote
 */
public interface Discounts {
    //判断优惠规则种类
    public boolean isScheme(Integer scheme);
    //匹配的优惠逻辑
    public Result<DTODiscounted> audit(VODiscounted voDiscounted);
    //获取优惠规则名称
    public String getName();

}

 策略接口的两个实现类(两种营销方案)

方案1:

package com.dragon.discount.strategy.impl;

import com.dragon.common.core.domain.Result;
import com.dragon.discount.common.domain.TCouponsType;
import com.dragon.discount.service.ITCouponsTypeService;
import com.dragon.discount.strategy.Discounts;
import com.dragon.discount.utils.SpringContextUtil;
import com.dragon.discount.common.domain.DTODiscounted;
import com.dragon.discount.common.domain.DiscountProduct;
import com.dragon.discount.common.domain.VODiscounted;
import com.dragon.order.common.domain.DTOOrder;
import com.dragon.order.common.domain.Order;
import com.dragon.order.remote.feign.OrderFeign;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;

/**
 * @author FangShiBa
 * @date 2024/3/3
 * @apiNote
 */
@Component
public class Discount1 implements Discounts {

    /**
     * 判断那种优惠券
     * @param scheme 优惠券类型编号
     * @return
     */
    @Override
    public boolean isScheme(Integer scheme) {
        return 1==scheme;
    }

    /**
     * 优惠逻辑
     * @param voDiscounted
     *     private  Integer orderId;           //订单编号
     *     private BigDecimal originalPrice;   //原总价
     *     private List<Product> products;     //商品信息
     *     private Integer couponsId;          //优惠券编号
     */
    @Override
    public Result<DTODiscounted> audit(VODiscounted voDiscounted) {
        //通过上下文注入获取service的bean
        OrderFeign orderFeign = SpringContextUtil.getBean(OrderFeign.class);
        //查询订单信息
        Result<Order> byOrderId = orderFeign.findByOrderId(voDiscounted.getOrderNumber());
        Order data = byOrderId.getData();
        //通过上下文注入获取service的bean
        ITCouponsTypeService itCouponsTypeService = SpringContextUtil.getBean(ITCouponsTypeService.class);
        //通过优惠券编号获取优惠券信息
        TCouponsType couponsType = itCouponsTypeService.selectTCouponsTypeByCouponsTypeId(voDiscounted.getCouponsId().longValue());
        //判断总价是否够满减金额
        if(couponsType.getFullPrice().compareTo(voDiscounted.getOriginalPrice())==1){
            return Result.fail("金额不够,小老弟,去凑单把");
        }
        //计算折后总价
        BigDecimal subtract = voDiscounted.getOriginalPrice().subtract(couponsType.getFavorable());
        //创建一个集合用来存放订单中所有商品信息(编号,折前折后价,等)
        ArrayList<DiscountProduct> products = new ArrayList<>();
        //计算每个商品折后的价格
        for (DiscountProduct product : voDiscounted.getProducts()) {
            BigDecimal productOriginalPrice = product.getProductPrice();
            //单件商品原价*(订单总折后价/订单总价)==单件商品折后价
            BigDecimal multiply = productOriginalPrice.multiply(subtract.divide(voDiscounted.getOriginalPrice(),2, RoundingMode.UP));
            //折后数据存入Product对象后放入List集合
            product.setProductDiscountPrice(multiply);
            //商品名称
            //将计算好的单个商品放入集合
            products.add(product);
        }
        //将计算好的总价,每个商品的折后价都放入一个新的订单对象中
        DTODiscounted dtoDiscounted = new DTODiscounted(data.getOrderNumber(), voDiscounted.getOriginalPrice(),subtract,products, couponsType.getCouponsTypeId().intValue());

        return Result.ok(dtoDiscounted);
    }
    @Override
    public String getName() {
        return "满100减20";
    }

}

 方案2:

package com.dragon.discount.strategy.impl;

import com.dragon.common.core.domain.Result;
import com.dragon.discount.common.domain.DiscountProduct;
import com.dragon.discount.common.domain.TCouponsType;
import com.dragon.discount.service.ITCouponsTypeService;
import com.dragon.discount.strategy.Discounts;
import com.dragon.discount.common.domain.DTODiscounted;
import com.dragon.discount.common.domain.VODiscounted;
import com.dragon.discount.utils.SpringContextUtil;
import com.dragon.order.common.domain.DTOOrder;
import com.dragon.order.common.domain.Order;
import com.dragon.order.remote.feign.OrderFeign;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;

/**
 * @author FangShiBa
 * @date 2024/3/3
 * @apiNote
 */
public class Discount2 implements Discounts {
    @Override
    public boolean isScheme(Integer scheme) {
        return 2==scheme;
    }

    @Override
    public Result<DTODiscounted> audit(VODiscounted voDiscounted) {

        //查找订单信息
        OrderFeign orderFeign = SpringContextUtil.getBean(OrderFeign.class);
        Result<Order> byOrderId = orderFeign.findByOrderId(voDiscounted.getOrderNumber());
        Order data = byOrderId.getData();


        ITCouponsTypeService itCouponsTypeService = SpringContextUtil.getBean(ITCouponsTypeService.class);
        //通过优惠券编号获取优惠券信息
        TCouponsType couponsType = itCouponsTypeService.selectTCouponsTypeByCouponsTypeId(voDiscounted.getCouponsId().longValue());
        //判断总价是否够满减金额
        if(couponsType.getFullPrice().compareTo(voDiscounted.getOriginalPrice())==1){
            return Result.fail("金额不够,小老弟,去凑单把");
        }
        //计算折后总价
        BigDecimal multiply1 = voDiscounted.getOriginalPrice().multiply(couponsType.getDiscount());
        ArrayList<DiscountProduct> products = new ArrayList<>();

        //计算每个商品折后的价格
        for (DiscountProduct product : voDiscounted.getProducts()) {

            BigDecimal productOriginalPrice = product.getProductPrice();
            //单件商品原价*(订单总折后价/订单总价)==单件商品折后价
            BigDecimal multiply = productOriginalPrice.multiply(multiply1.divide(voDiscounted.getOriginalPrice(),2, RoundingMode.UP));
            //折后数据存入Product对象后放入List集合
            product.setProductDiscountPrice(multiply);
            products.add(product);
        }
        // TODO: 2024/3/4 voDiscounted.getOrderId()是主键,换成orderNumber
        DTODiscounted dtoDiscounted = new DTODiscounted(data.getOrderNumber(), voDiscounted.getOriginalPrice(),multiply1,products, couponsType.getCouponsTypeId().intValue());

        return Result.ok(dtoDiscounted);
    }

    @Override
    public String getName() {
        return null;
    }
}
  • 12
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值