用责任链模式改造 if else

ops/2024/12/23 1:09:45/

我的上一篇文章,因为if else 多了,捣鼓很久,今天用责任链模式改造一下。

代码写着写着,if else if 逻辑忘记了,哎。。。-CSDN博客
责任链模式(Chain of Responsibility Pattern)
1. 什么是责任链模式
责任链模式是一种行为设计模式,它允许请求沿着处理者链传递,直到其中一个处理者处理它。每个处理者都可以决定是否处理请求或者将其传递给链中的下一个处理者。
2. 责任链模式的优点
降低耦合度:请求发送者不需要知道请求的最终处理者是谁,只需要知道请求会被某个处理者处理。
灵活配置处理链:可以根据需要动态地增加或删除处理者,而不影响其他处理者。
增强系统扩展性:新的处理者可以很容易地添加到链中,从而扩展系统的功能。
3. 责任链模式的应用场景
权限控制:多个权限检查器组成一个链,逐级检查用户的权限。
日志处理:多个日志处理器组成一个链,逐级处理日志消息。
支付处理:多种支付方式组成一个链,逐级处理支付请求。
4. 责任链模式的实现
现在如下代码改成 责任链模式

java">        //代理价>销售价if (agentPrice.compareTo(goodsPrice) > 0) {isNeedLock=true;reason="代理价>销售价";reasonType="1";log.info("agentPrice.compareTo(goodsPrice) > 0 ");}else if (agentPrice.compareTo(BigDecimal.ZERO) > 0) {//(销售价-代理价)/代理价<5%double num = (goodsPrice.subtract(agentPrice)).divide(agentPrice,6, RoundingMode.HALF_UP).multiply(new BigDecimal(100)).doubleValue();if (num < 5) {isNeedLock=true;reason="(销售价-代理价)/代理价<5%";reasonType="2";log.info("agentPrice.compareTo(BigDecimal.ZERO) > 0");}}else if (supplyPrice.compareTo(agentPrice) > 0) {isNeedLock = true;reason = "供货价大于代理价";reasonType = "5";log.info(" supplyPrice.compareTo(agentPrice) > 0 ");}

首先分析需要代码,这里的每一个 if else 都有机会执行,一个执行了,其他的 if else 就不会执行了。

入参需要三个价格,那么可以将这个价格放到一个类里面, 这里执行结果有四种,那么可以创建一个枚举类存放,可以在初始化入参的时候设置为默认枚举。

入参请求和结果类 PriceCheckRequest 

java">/*** @author hds*/
@Data
public class PriceCheckRequest {private BigDecimal goodsPrice;private BigDecimal agentPrice;private BigDecimal supplyPrice;private PriceCheckEnum priceCheckEnum;public PriceCheckRequest(BigDecimal goodsPrice, BigDecimal agentPrice, BigDecimal supplyPrice) {this.goodsPrice = goodsPrice;this.agentPrice = agentPrice;this.supplyPrice = supplyPrice;}public PriceCheckRequest(Product product) {this.goodsPrice = Optional.ofNullable(product.getProductPrice()).orElse(BigDecimal.ZERO);this.agentPrice = Optional.ofNullable(product.getAgentPrice()).orElse(BigDecimal.ZERO);this.supplyPrice = Optional.ofNullable(product.getSupplyPrice()).orElse(BigDecimal.ZERO);priceCheckEnum = PriceCheckEnum.DEFAULT;}
}

结果枚举类

java">@Getter
public enum PriceCheckEnum {/*    request.setNeedLock(true);request.setReason("代理价>销售价");request.setReasonType("1");request.setNeedLock(true);request.setReason("(销售价-代理价)/代理价<5%");request.setReasonType("2");request.setNeedLock(true);request.setReason("供货价大于代理价");request.setReasonType("5");*/DEFAULT("0", "", false),AGENT_PRICE_GREATER_THAN_SALE_PRICE("1", "代理价>销售价", true),SALE_PRICE_DIFFERENCE_PERCENTAGE("2", "(销售价-代理价)/代理价<5%", true),SUPPLIER_PRICE_GREATER_THAN_AGENT_PRICE("5", "供货价>代理价", true);private final String reasonType;private final String reason;private final Boolean needLock;PriceCheckEnum(String reasonType, String reason, boolean needLock) {this.reasonType = reasonType;this.reason = reason;this.needLock = needLock;}

解下类就要创建一个 价格检查的抽象类 

PriceCheckHandler 其中 next 属性是执行 下一个处理器
java">@Setter
public abstract class PriceCheckHandler {protected PriceCheckHandler next;public abstract void handle(PriceCheckRequest request);public  void check(PriceCheckRequest request){if (!request.getPriceCheckEnum().getNeedLock()){if (next != null) {next.handle(request);}}}
}

代理价大于销售价 处理器

AgentPriceGreaterThanGoodsPriceHandler
java">public class AgentPriceGreaterThanGoodsPriceHandler extends PriceCheckHandler {@Overridepublic void handle(PriceCheckRequest request) {if (BigDecimalUtil.isGreaterThan(request.getAgentPrice(),request.getGoodsPrice())) {request.setPriceCheckEnum(PriceCheckEnum.AGENT_PRICE_GREATER_THAN_SALE_PRICE);}check(request);}
}

供货价大于代理价处理器

SupplyPriceGreaterThanAgentPriceHandler
java">public class SupplyPriceGreaterThanAgentPriceHandler extends PriceCheckHandler {@Overridepublic void handle(PriceCheckRequest request) {if (BigDecimalUtil.isGreaterThan( request.getSupplyPrice(), request.getAgentPrice())) {request.setPriceCheckEnum(PriceCheckEnum.SUPPLIER_PRICE_GREATER_THAN_AGENT_PRICE);}check(request);}
}
(销售价-代理价)/代理价<5% 处理器
AgentPricePercentageDifferenceHandler
java">public class AgentPricePercentageDifferenceHandler extends PriceCheckHandler {@Overridepublic void handle(PriceCheckRequest request) {if ( BigDecimalUtil.isGreaterThan(request.getAgentPrice(),BigDecimal.ZERO) ) {double num = (request.getGoodsPrice().subtract(request.getAgentPrice())).divide(request.getAgentPrice(), 6, RoundingMode.HALF_UP).multiply(new BigDecimal(100)).doubleValue();if (num < 5) {request.setPriceCheckEnum(PriceCheckEnum.SALE_PRICE_DIFFERENCE_PERCENTAGE);}check(request);}check(request);}
}

默认处理器

DefaultPriceHandler 默认返回价格检查通过,需要把它放在责任链的最后处理器
java">public class DefaultPriceHandler extends PriceCheckHandler {@Overridepublic void handle(PriceCheckRequest request) {request.setPriceCheckEnum(PriceCheckEnum.DEFAULT);}
}

责任链创建类 (简单的建造者模式)

ChainBuilder
java">public class ChainBuilder {private PriceCheckHandler head;public static ChainBuilder chainBuilder = new ChainBuilder();static {chainBuilder.addFirst(new DefaultPriceHandler());chainBuilder.addFirst(new AgentPricePercentageDifferenceHandler());chainBuilder.addFirst(new SupplyPriceGreaterThanAgentPriceHandler());chainBuilder.addFirst(new AgentPriceGreaterThanGoodsPriceHandler());}public void addFirst(PriceCheckHandler handler) {handler.setNext(head);head = handler;}public void process(PriceCheckRequest request) {if (head != null) {head.handle(request);}}
}

最后测试

java">
@Slf4j
public class ChainBuilderTest {@Testpublic void testChain(){Product product = new Product();product.setAgentPrice(new BigDecimal("59.00"));product.setProductPrice(new BigDecimal("60.00"));product.setSupplyPrice(new BigDecimal("50.00"));PriceCheckRequest priceCheckRequest = new PriceCheckRequest(product);ChainBuilder.chainBuilder.process(priceCheckRequest);log.info("商品价格校验结果:{}", JSONUtil.toJsonStr(priceCheckRequest) );product.setAgentPrice(new BigDecimal("70.00"));product.setProductPrice(new BigDecimal("60.00"));product.setSupplyPrice(new BigDecimal("50.00"));//AGENT_PRICE_GREATER_THAN_SALE_PRICEpriceCheckRequest = new PriceCheckRequest(product);ChainBuilder.chainBuilder.process(priceCheckRequest);log.info("商品价格校验结果:{}", JSONUtil.toJsonStr(priceCheckRequest) );product.setAgentPrice(new BigDecimal("60.00"));product.setProductPrice(new BigDecimal("60.00"));product.setSupplyPrice(new BigDecimal("80.00"));//SUPPLIER_PRICE_GREATER_THAN_AGENT_PRICEpriceCheckRequest = new PriceCheckRequest(product);ChainBuilder.chainBuilder.process(priceCheckRequest);log.info("商品价格校验结果:{}", JSONUtil.toJsonStr(priceCheckRequest) );product.setAgentPrice(new BigDecimal("60.00"));product.setProductPrice(new BigDecimal("80.00"));product.setSupplyPrice(new BigDecimal("60.00"));//DEFAULTpriceCheckRequest = new PriceCheckRequest(product);ChainBuilder.chainBuilder.process(priceCheckRequest);log.info("商品价格校验结果:{}", JSONUtil.toJsonStr(priceCheckRequest) );}}

输出结果,

好了今天就到这里,有兴趣的同学可以自己试一下。

另外将 AgentPricePercentageDifferenceHandler 放到倒数第二个,是可以延迟计算。

还可以再在处理类处理了请求的时候,将处理次数加一进行统计,经过一段时间,用定时任务统计每个处理器的次数,将次数多的处理器动态调整放到前面。


http://www.ppmy.cn/ops/120779.html

相关文章

【教程】57帧! Mac电脑流畅运行黑神话悟空

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 1、先安装CrossOver。网上有许多和谐版&#xff0c;可自行搜索。&#xff08;pd虚拟机里运行黑神话估计够呛的&#xff09; 2、运行CrossOver&#xf…

CSS 圆形边框与阴影

目录 1. 圆角边框 1.1 正圆 1.2 圆角矩形 1.3 任意圆角 1.4 某个圆角 2. 盒子阴影 3. 文字阴影 1. 圆角边框 1.1 正圆 1.2 圆角矩形 1.3 任意圆角 1.4 某个圆角 2. 盒子阴影 3. 文字阴影

vue基于Spring Boot框架的高校实验室预约管理系统

目录 毕设制作流程功能和技术介绍系统实现截图开发核心技术介绍&#xff1a;使用说明开发步骤编译运行代码执行流程核心代码部分展示可行性分析软件测试详细视频演示源码获取 毕设制作流程 &#xff08;1&#xff09;与指导老师确定系统主要功能&#xff1b; &#xff08;2&am…

React 组件命名规范

在 React 项目中&#xff0c;如果希望保持组件命名的一致性&#xff0c;并防止在引入时出现不同名称的问题&#xff0c;可以遵循以下的组件规范&#xff1a; 1、默认导出组件&#xff1a; 所有特殊要求的组件&#xff08;如页面组件或根组件&#xff09;应该使用 export defau…

STM32F103C8----3-3 蜂鸣器(跟着江科大学STM32)

一&#xff0c;电路图 &#xff08;接线图&#xff09; 面包板的的使用请参考&#xff1a;《面包板的使用_面包板的详细使用方法-CSDN博客》 二&#xff0c;目的/效果 3-3 蜂鸣器 三&#xff0c;创建Keil项目 详细参考&#xff1a;《STM32F103C8----2-1 Keil5搭建STM32项目模…

express,生成用户登录后的 token

在 Node.js 中使用 Express 框架生成用户登录后的 token&#xff0c;通常会涉及到以下几个步骤&#xff1a; 设置 Express 应用&#xff1a;首先&#xff0c;你需要有一个基本的 Express 应用。安装必要的中间件&#xff1a;例如 jsonwebtoken&#xff08;JWT&#xff09;用于…

<STC32G12K128入门第十六步>获取NTP网络时间

前言 这里主要讲解如何通过NTP服务器获取网络时间。 一、NTP是什么? NTP全名“Network TimeProtocol”,即网络时间协议,是由RFC 1305定义的时间同步协议,用来在分布式时间服务器和客户端之间进行时间同步。 NTP基于UDP报文进行传输,使用的UDP端口号为123。使用NTP的目的…

【每日一题】LeetCode 2516.每种字符至少取k个(哈希表、字符串、滑动窗口)

【每日一题】LeetCode 2516.每种字符至少取k个&#xff08;哈希表、字符串、滑动窗口&#xff09; 题目描述 给定一个由字符 ‘a’、‘b’、‘c’ 组成的字符串 s 和一个非负整数 k。每分钟&#xff0c;你可以选择取走 s 最左侧或最右侧的那个字符。 你必须取走每种字符至少…