首先我们要知道策略模式的使用场景
- 购物车优惠
- 排序算法
- 游戏AI决策
- .......等等
我认为策略模式就是对开闭原则的一种很好的体现.对添加开放,对修改,删除关闭,使系统更加灵活,易于扩展和维护
最常用的就是营销策略,所以示例是做的一个营销策略的策略接口
首先我们先创建一个接口,里面需要有三个方法
- 判断优惠规则,返回一个布尔类型
- 如果第一个方法判断为true,那么将这个策略规则返回
- 策略规则的名称(可以不用,根据业务需求定)
然后去实现这个借口,一个实现类就是一种优惠方案
做完这些我们的策略接口就写好了,然后再去实现怎么调用它
我们需要创建一个类,里面将所有的策略方案创建出来放入一个集合中
(这里使用到了单例模式和工厂模式)
然后我们写一个方法,带着传过来的优惠券编号去数据库查找优惠券的信息(我的数据库是有一个字段记录的优惠券类型 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;
}
}