SpringBoot 模板模式实现优惠券逻辑

news2024/11/24 10:04:56

一、计算逻辑的类结构图

 在这张图里,顶层接口 RuleTemplate 定义了 calculate 方法,抽象模板类 AbstractRuleTemplate 将通用的模板计算逻辑在 calculate 方法中实现,同时它还定义了一个抽象方法 calculateNewPrice 作为子类的扩展点。各个具体的优惠计算类通过继承 AbstractRuleTemplate,并实现 calculateNewPrice 来编写自己的优惠计算方式。

二、代码实现

1、RuleTemplate.java

public interface RuleTemplate {

    // 计算优惠券
    ShoppingCart calculate(ShoppingCart settlement);
}

2、AbstractRuleTemplate.java

public ShoppingCart calculate(ShoppingCart order) {
    // 获取订单总价
    Long orderTotalAmount = getTotalPrice(order.getProducts());
    // 获取以shopId为维度的总价统计
    Map<Long, Long> sumAmount = getTotalPriceGroupByShop(order.getProducts());
    CouponTemplateInfo template = order.getCouponInfos().get(0).getTemplate();
    // 最低消费限制
    Long threshold = template.getRule().getDiscount().getThreshold();
    // 优惠金额或者打折比例
    Long quota = template.getRule().getDiscount().getQuota();
    // 如果优惠券未指定shopId,则shopTotalAmount=orderTotalAmount
    // 如果指定了shopId,则shopTotalAmount=对应门店下商品总价
    Long shopId = template.getShopId();
    Long shopTotalAmount = (shopId == null) ? orderTotalAmount : sumAmount.get(shopId);
    
    // 如果不符合优惠券使用标准, 则直接按原价走,不使用优惠券
    if (shopTotalAmount == null || shopTotalAmount < threshold) {
        log.debug("Totals of amount not meet");
        order.setCost(orderTotalAmount);
        order.setCouponInfos(Collections.emptyList());
        return order;
    }
    // 子类中实现calculateNewPrice计算新的价格
    Long newCost = calculateNewPrice(orderTotalAmount, shopTotalAmount, quota);
    if (newCost < minCost()) {
        newCost = minCost();
    }
    order.setCost(newCost);
    log.debug("original price={}, new price={}", orderTotalAmount, newCost);
    return order;
}

3、子类

MoneyOffTemplate.java

@Slf4j
@Component
public class MoneyOffTemplate extends AbstractRuleTemplate implements RuleTemplate {
    @Override
    protected Long calculateNewPrice(Long totalAmount, Long shopAmount, Long quota) {
        // benefitAmount是扣减的价格
        // 如果当前门店的商品总价<quota,那么最多只能扣减shopAmount的钱数
        Long benefitAmount = shopAmount < quota ? shopAmount : quota;
        return totalAmount - benefitAmount;
    }    
}

4、工厂类

CouponTemplateFactory.java

@Component
@Slf4j
public class CouponTemplateFactory {

    @Autowired
    private MoneyOffTemplate moneyOffTemplate;

    @Autowired
    private DiscountTemplate discountTemplate;

    @Autowired
    private RandomReductionTemplate randomReductionTemplate;

    @Autowired
    private LonelyNightTemplate lonelyNightTemplate;

    @Autowired
    private DummyTemplate dummyTemplate;
    @Autowired
    private AntiPauTemplate antiPauTemplate;

    public RuleTemplate getTemplate(ShoppingCart order) {
        // 不使用优惠券
        if (CollectionUtils.isEmpty(order.getCouponInfos())) {
            // dummy模板直接返回原价,不进行优惠计算
            return dummyTemplate;
        }

        // 获取优惠券的类别
        // 目前每个订单只支持单张优惠券
        CouponTemplateInfo template = order.getCouponInfos().get(0).getTemplate();
        CouponType category = CouponType.convert(template.getType());

        switch (category) {
            // 订单满减券
            case MONEY_OFF:
                return moneyOffTemplate;
            // 随机立减券
            case RANDOM_DISCOUNT:
                return randomReductionTemplate;
            // 午夜下单优惠翻倍
            case LONELY_NIGHT_MONEY_OFF:
                return lonelyNightTemplate;
            // 打折券
            case DISCOUNT:
                return discountTemplate;
            case ANTI_PUA:
                return antiPauTemplate;
            // 未知类型的券模板
            default:
                return dummyTemplate;
        }
    }

}

5、使用

CouponCalculationServiceImpl.java

    @Autowired
    private CouponTemplateFactory couponProcessorFactory;

    // 优惠券结算
    // 这里通过Factory类决定使用哪个底层Rule,底层规则对上层透明
    @Override
    public ShoppingCart calculateOrderPrice(@RequestBody ShoppingCart cart) {
        log.info("calculate order price: {}", JSON.toJSONString(cart));
        RuleTemplate ruleTemplate = couponProcessorFactory.getTemplate(cart);
        return ruleTemplate.calculate(cart);
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/910363.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ES6 代理

一、代理 Proxy 用于修改某些操作的默认行为&#xff0c;等同于在语言层面做出修改&#xff0c;所以属于一种“元编程”&#xff08;meta programming&#xff09;&#xff0c;即对编程语言进行编程。 Proxy 可以理解成&#xff0c;在目标对象之前架设一层“拦截”&#xff0…

比钻石还要硬硬40倍,有望被用来造宇宙飞船的新材料——碳炔

硬度是一种物理性质&#xff0c;它代表物质抵抗被划伤或变形的能力。硬度可以用不同的方法来测量&#xff0c;常见的有维氏硬度、摩氏硬度、布氏硬度等。其中&#xff0c;摩氏硬度是最简单也最常用的一种&#xff0c;它是根据不同物质之间能否互相划伤来排列出一个从1到10的等级…

nginx复现问题accept4() failed (24: Too many open files)

nginx在近两天连接数上去的时候业务有影响&#xff0c;错误日志频繁出现accept4() failed (24: Too many open files)报错信息&#xff0c;后续业务低峰自动恢复&#xff0c;以3种方式复现测试会报错的原因记录如下 请求模拟&#xff1a;使用nginx反向代理一个java后端 请求工…

MySQL数据库——SQL(4)-DCL(管理用户、权限控制)

目录 管理用户 1.查询用户 2.创建用户 3.修改用户密码 4.删除用户 示例 权限控制 1.查询权限 2.授予权限 3.撤销权限 示例 DCL总结 DCL DCL英文全称是Data Control Language&#xff08;数据控制语言&#xff09;&#xff0c;用来管理数据库用户、控制数据库的访问…

vue3 tailwindcss的使用

首先安装依赖&#xff1a; npm install -D tailwindcsslatest postcsslatest autoprefixerlatestnpm i -D unocss 然后vite.config.ts中 引入 import Unocss from unocss/viteexport default defineConfig({plugins: [Unocss(),],})终端执行&#xff1a; npx tailwindcss in…

如何让智能搜索引擎更灵活、更高效?

随着互联网的发展和普及&#xff0c;搜索引擎已经成为人们获取信息、解决问题的主要工具之一。 然而&#xff0c;传统的搜索引擎在面对大数据时&#xff0c;往往存在着搜索效率低下、搜索结果精准度不够等问题。 为了解决这些问题&#xff0c;越来越多的企业开始采用智能搜索技…

PHPStudy 安装tp8 php8.2.9

一、PhpStudy升级PHP版本&#xff0c;安装PHP8.2操作步骤 1.1、官网下载最新的php版本 打开Windows版的官网下载&#xff0c;地址&#xff1a;https://windows.php.net/download/ 页面上有不同的PHP版本&#xff0c;这里我们下载的是64位nts版的PHP8.2.9。 1.2、解压下载的文…

Spring cache整合Redis使用介绍

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

【附安装包】Revit2024安装教程

软件下载 软件&#xff1a;Revit版本&#xff1a;2024语言&#xff1a;简体中文大小&#xff1a;10.05G安装环境&#xff1a;Win11/Win10/Win8/Win7硬件要求&#xff1a;CPU3.0GHz 内存8G(或更高&#xff09;下载通道①百度网盘丨64位下载链接&#xff1a;https://pan.baidu.c…

JSON的处理

1、JSON JSON(JavaScript Object Notation)&#xff1a;是一种轻量级的数据交换格式。 它是基于 ECMAScript 规范的一个子集&#xff0c;采用完全独立于编程语言的文本格式来存储和表示数据。 简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。易于人阅读和编写&#…

PySpark安装及WordCount实现(基于Ubuntu)

先盘点一下要安装哪些东西&#xff1a; VMwareubuntu 14.04&#xff08;64位&#xff09;Java环境&#xff08;JDK 1.8&#xff09;Hadoop 2.7.1Spark 2.4.0&#xff08;Local模式&#xff09;Pycharm &#xff08;一&#xff09;Ubuntu VMware 和 ubuntu 14.04&#xff08;…

【bug记录】ios动画闪烁,@keyframe动画在100%的时候设置为opacity:0,最后一帧会变成opacity:1

背景 前段时间需要实现一个水波纹扩散效果&#xff0c;大概效果就两点&#xff1a;波纹逐渐扩散&#xff0c;半径逐渐增大&#xff1b;透明度逐渐降低&#xff08;如下图&#xff09;。本以为这就是一个简单的动画&#xff0c;很轻松就实现了。但是发布之后测试同学反馈&#…

Allegro如何设置Net Class在物理和间距规则中同步操作指导

Allegro如何设置Net Class在物理和间距规则中同步操作指导 在用Allegro设置规则的时候,设置net class是必要的操作,时常需要在物理和间距规则都设置好Class,如果物理和间距规则中都单独去设置的话比较费时间。如下图Net Class 下面介绍如何将物理和间距规则中的Class同步起来…

AgentBench:AI智能体的应用前景——消费端的应用

从应用前景上看,AI智能体既可以被用于消费端来提升用户的使用体验,也可以被用于生产端来作为重要的生产力工具。 1、消费端的应用 在消费端,AI智能体将凭借其强大的能力取代现有的聊天机器人,并应用到广泛的领域。聊天机器人目前已比较普及,比如苹果的Siri、亚马逊的A…

Java学习笔记39

Java笔记39 反射机制 静态/动态语言 动态语言 是一类在运行时可以改变其结构的语言&#xff1a;例如新的函数、对象、甚至代码可以被引进&#xff0c;已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构。主要动态语言&#…

学习记录——FLatten Transformer

FLatten Transformer: Vision Transformer using Focused Linear Attention ICCV 2023 聚焦式线性注意力模块 关于Transformer 在Transformer模型应用于视觉领域的过程中&#xff0c;降低自注意力的计算复杂度是一个重要的研究方向。线性注意力通过两个独立的映射函数来近似S…

【图解】多层感知器(MLP)

图片是一个多层感知器&#xff08;MLP&#xff09;的示意图&#xff0c;它是一种常见的神经网络模型&#xff0c;用于从输入到输出进行非线性映射。图片中的网络结构如下&#xff1a;

python 打印沁园春 雪 居中对齐 文本对齐

以下是python 中使用 DebugInfo 模块居中对齐打印《沁园春・雪》的效果 引入模块 pip install DebugInfopython代码 # -*- coding:UTF-8 -*-# region 引入必要依赖 from DebugInfo.DebugInfo import * # endregion诗文 沁园春 雪 作者: 毛主席 北国风光&#xff0c;千里冰封…

12312321312

目录 层次分析法(AHP) 基本步骤 建立层次模型 构造判断矩阵 一致性检验 求得权重 填表得结果 一点补充 详细做法补充 特征向量含义思考 一些问题 优劣解距离法(TOPSIS) 基本思想 模型步骤 数据处理 指标正向化 标准化处理 计算得分 *结果处理 熵权法 模型思…

【【萌新的STM32学习-12】】

萌新的STM32学习-12 GPIO八种模式 1输入浮空 输入用&#xff0c;完全浮空&#xff0c;状态不定 2输入上拉 输入用&#xff0c;用内部上拉&#xff0c;默认是高电平 3输入下拉 输入用&#xff0c;用内部下拉&#xff0c;默认是低电平 4模拟功能 ADC DAC 5开漏输出 软件IIC的…