让YOLO飞起来:从CPU到GPU的配置指南

睬永镭木责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。

更简单的描述是:责任链是一个链表结构,这条链上有多个节点,它们有相同的接口,各自有各自的责任和实现。当有数据输入时,第一个节点看自己能否处理问题,如果可以就进行处理,如果不能就数据交给下一个节点进行处理,以此类推直到最后一个责任节点。

责任链模式的使用场景是:

有多个对象可以处理同一个请求,具体由哪个对象处理是在运行时确定的。

例如,有 ABC 三个处理者可以处理一个请求,请求 a 需要 AC 两个处理者处理,请求 b 需要 BC 两个处理者处理,同时两个处理者之间可能有前后依赖关系,这时候就可以使用责任链模式

在不确定请求处理者的时候,向同一类型的处理者中的一个发送请求

02 例子

笔者曾经通过责任链模式优化神州专车支付流程 。

支付流程是通过定时任务执行,每次都需要去判断用户的账号余额、优惠券、企业账号余额是否可以抵扣,假如满足条件,则从对应的账号资产里扣除对应的金额 。

因为原来的代码存在大量的 if/else 逻辑,业务逻辑相互杂糅,维护成本很高,勇哥花了一周时间重构了该逻辑 , 以下是演示伪代码:

1、定义抽象处理者(Handler)

/**

* 支付处理器接口

* 定义所有支付方式需要实现的方法

*/

public interface PaymentHandler {

/**

* 判断该支付处理器是否适用于当前用户

* @param userId 用户ID

* @return 是否适用

*/

boolean canProcess(String userId);

/**

* 执行支付操作

* @param userId 用户ID

* @param amount 支付金额

* @return 支付结果

*/

PaymentResult processPayment(String userId, double amount);

}

/**

* 支付结果类

* 封装支付操作的结果信息

*/

class PaymentResult {

private boolean success; // 支付是否成功

private double paidAmount; // 实际支付金额

private String message; // 支付结果描述信息

public PaymentResult(boolean success, double paidAmount, String message) {

this.success = success;

this.paidAmount = paidAmount;

this.message = message;

}

// Getter方法

public boolean isSuccess() {

return success;

}

public double getPaidAmount() {

return paidAmount;

}

public String getMessage() {

return message;

}

}

2、定义具体处理者(Concrete Handler)

/**

* 企业账户支付处理器实现

*/

public class CorporatePaymentHandler implements PaymentHandler {

private static final double MAX_CORPORATE_PAYMENT = 5000; // 企业账户最大支付限额

@Override

public boolean canProcess(String userId) {

// 只有以"emp_"开头的用户ID才能使用企业账户支付

return userId.startsWith("emp_");

}

@Override

public PaymentResult processPayment(String userId, double amount) {

System.out.printf("尝试使用企业账户支付: 用户[%s], 金额[%.2f]%n", userId, amount);

if (amount <= MAX_CORPORATE_PAYMENT) {

// 金额在限额内,全额支付

return new PaymentResult(true, amount, "企业账户支付成功");

} else {

// 超过限额,只支付限额部分

return new PaymentResult(true, MAX_CORPORATE_PAYMENT,

String.format("企业账户部分支付成功(%.2f),还需支付: %.2f",

MAX_CORPORATE_PAYMENT, amount - MAX_CORPORATE_PAYMENT));

}

}

}

/**

* 个人账户支付处理器实现

*/

public class PersonalPaymentHandler implements PaymentHandler {

private static final double MAX_PERSONAL_PAYMENT = 1000; // 个人账户最大支付限额

@Override

public boolean canProcess(String userId) {

// 所有用户都可以使用个人账户支付

return true;

}

@Override

public PaymentResult processPayment(String userId, double amount) {

System.out.printf("尝试使用个人账户支付: 用户[%s], 金额[%.2f]%n", userId, amount);

if (amount <= MAX_PERSONAL_PAYMENT) {

// 金额在限额内,全额支付

return new PaymentResult(true, amount, "个人账户支付成功");

} else {

// 超过限额,只支付限额部分

return new PaymentResult(true, MAX_PERSONAL_PAYMENT,

String.format("个人账户部分支付成功(%.2f),还需支付: %.2f",

MAX_PERSONAL_PAYMENT, amount - MAX_PERSONAL_PAYMENT));

}

}

}

3、定义组合支付上下文(核心数据结构是链表)

/**

* 组合支付上下文

* 负责管理支付处理器并执行组合支付

*/

public class CompositePaymentContext {

private final List handlers = new ArrayList<>();

/**

* 添加支付处理器

* @param handler 支付处理器实例

*/

public void addHandler(PaymentHandler handler) {

handlers.add(handler);

}

/**

* 执行组合支付

* @param userId 用户ID

* @param totalAmount 总支付金额

* @return 支付结果映射表,key为处理器类名,value为支付结果

*/

public Map executePayment(String userId, double totalAmount) {

// 使用LinkedHashMap保持支付尝试的顺序

Map paymentResults = new LinkedHashMap<>();

double remaining = totalAmount; // 剩余待支付金额

// 按处理器顺序尝试支付

for (PaymentHandler handler : handlers) {

// 检查处理器是否适用且还有金额需要支付

if (handler.canProcess(userId) && remaining > 0) {

// 执行支付

PaymentResult result = handler.processPayment(userId, remaining);

// 记录支付结果

paymentResults.put(handler.getClass().getSimpleName(), result);

if (result.isSuccess()) {

// 支付成功,减少剩余金额

remaining -= result.getPaidAmount();

if (remaining <= 0) {

break; // 金额已支付完成,退出循环

}

}

}

}

// 如果还有剩余金额未支付,记录剩余金额

if (remaining > 0) {

paymentResults.put("Remaining", new PaymentResult(false, remaining,

String.format("支付未完成,剩余金额: %.2f", remaining)));

}

return paymentResults;

}

}

4、测试类

/**

* 组合支付系统演示类

*/

public class CompositePaymentSystem {

public static void main(String[] args) {

// 初始化支付上下文

CompositePaymentContext paymentContext = new CompositePaymentContext();

// 注册支付处理器(顺序决定了支付尝试的优先级)

paymentContext.addHandler(new CorporatePaymentHandler()); // 先尝试企业账户

paymentContext.addHandler(new PersonalPaymentHandler()); // 再尝试个人账户

// 测试用例1:企业用户,只需企业账户支付

System.out.println("\n=== 测试用例1 ===");

System.out.println("用户ID: emp_789, 支付金额: 3000.00");

Map results1 = paymentContext.executePayment("emp_789", 3000);

results1.forEach((handlerName, result) -> {

System.out.printf("[%s] %s (支付金额: %.2f)%n",

handlerName, result.getMessage(), result.getPaidAmount());

});

// 测试用例2:企业用户,需要组合支付

System.out.println("\n=== 测试用例2 ===");

System.out.println("用户ID: emp_789, 支付金额: 6000.00");

Map results2 = paymentContext.executePayment("emp_789", 6000);

results2.forEach((handlerName, result) -> {

System.out.printf("[%s] %s (支付金额: %.2f)%n",

handlerName, result.getMessage(), result.getPaidAmount());

});

// 测试用例3:个人用户,只需个人账户支付

System.out.println("\n=== 测试用例3 ===");

System.out.println("用户ID: user123, 支付金额: 1500.00");

Map results3 = paymentContext.executePayment("user123", 1500);

results3.forEach((handlerName, result) -> {

System.out.printf("[%s] %s (支付金额: %.2f)%n",

handlerName, result.getMessage(), result.getPaidAmount());

});

}

}

4 规则引擎

01 概念

电商系统中,经常会有营销活动,比如支付订单时给与用户一定程度的优惠,比如活动规则:满 1000 减200 ,满 500 减 100 。

这种情况一般都是通过 if-else 做分支判断处理,还是非常简单的。

但假如需要频繁的修改活动规则,那么就需要频繁的修改代码,非常不容易维护(开发成本 + 上线成本)。

此时,引入规则引擎有顺其自然了。规则引擎的优势如下:

降低开发成本

业务人员独立配置业务规则,开发人员无需理解,以往需要业务人员告诉开发人员,开发人员需要理解才能开发,并且还需要大量的测试来确定是否正确,而且开发结果还容易和提出的业务有偏差,种种都导致开发成本上升

增加业务的透明度,业务人员配置之后其它人业务人员也能看到

提高了规则改动的效率和上线的速度

通过规则引擎,我们只需要将业务人员配置的规则转换成一个规则字符串,然后将该规则字符串保存进数据库中,当使用该规则时,只传递该规则所需要的参数,便可以直接计算出结果。

02 例子

回到刚才营销活动 ,使用 AviatorScript 规则引擎的流程如下:

1、创建运营脚本,将脚本存储在数据库 或者 配置中心。

if (amount>=1000){

return 200;

}elsif(amount>=500){

return 100;

}else{

return 0;

}

2、定义调用方法 。

public static BigDecimal getDiscount(BigDecimal amount, String rule) {

// 执行规则并计算最终价格

Map env = new HashMap();

env.put("amount", amount);

Expression expression = AviatorEvaluator.compile(

DigestUtils.md5Hex(rule.getBytes()),

rule,

true);

Object result = expression.execute(env);

if (result != null) {

return new BigDecimal(String.valueOf(result));

}

return null;

}

3、执行测试例子

// step1 : 此处可以从配置中心 或者数据库中获取

String rule = "if (amount>=1000){\n" +

" return 200;\n" +

"}elsif(amount>=500){\n" +

" return 100;\n" +

"}else{\n" +

" return 0;\n" +

"}\n";

// step 2: 通过 AviatorScript 执行

BigDecimal discount = getDiscount(new BigDecimal("600"), rule);

System.out.println("discount:" + discount);

// 执行结果是: discount:100

测试类地址:

5 总结

在实际开发中,我们经常会遇到需要根据不同条件执行不同逻辑的场景。

传统的if-else嵌套方式虽然直观,但随着业务复杂度增加,会导致代码臃肿、可读性差、维护困难等问题。

本文总结了四种优雅的设计模式来解决这类"条件爆炸"问题。

01. 策略模式:灵活切换策略

核心思想:定义一系列算法,将每个算法封装起来,并使它们可以相互替换。

适用场景:

系统中有多个相似的类,仅在行为上有差异

需要在运行时动态选择算法

需要避免暴露复杂的条件判断

优势:

符合开闭原则,易于扩展新策略

消除大量条件语句

算法可以自由切换

示例:支付系统中不同支付方式的处理,如信用卡、支付宝、微信支付等。

02. SPI机制:服务发现的优雅实现

核心思想:通过配置文件动态发现和加载服务实现。

适用场景:

需要实现插件化架构

服务提供方需要独立于服务调用方

需要运行时动态发现服务

优势:

实现完全解耦

新增实现无需修改主代码

支持热插拔

示例:JDBC驱动加载、Dubbo的扩展点实现。

03. 责任链模式:处理流程的链式传递

核心思想:将请求的发送者和接收者解耦,使多个对象都有机会处理请求。

适用场景:

有多个对象可以处理同一请求

需要动态指定处理流程

处理顺序很重要

优势:

降低耦合度

灵活调整处理顺序

新增处理器方便

示例:支付流程中的多账户组合支付、审批流程等。

04. 规则引擎:业务规则的动态管理

核心思想:将业务规则从代码中分离,实现动态配置。

适用场景:

业务规则频繁变化

需要非技术人员配置规则

规则复杂度高

优势:

业务人员可自主配置

降低开发成本

提高规则透明度

示例:营销活动规则、风控规则等。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值