news 2026/4/16 13:41:42

设计模式-

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
设计模式-

策略工厂

定义策略接口,多个实现类,定义策略工厂,构造方法通过Spring 容器自动获取实现类List集合,遍历List按照每个实现类策略类型逐个插入Map

public interface PayHandler { void pay(PayCommand command); String getPayType(); // 获取支付类型(例如:支付宝,微信) } @Service("ALI") public class AliPayHandler implements PayHandler { @Override public void pay(PayCommand command) { // 支付宝支付逻辑 System.out.println("支付宝支付,支付金额:" + command.getAmount()); } @Override public String getPayType() { return "ALI"; // 支付宝支付类型 } } @Service("WECHAT") public class WeChatPayHandler implements PayHandler { @Override public void pay(PayCommand command) { // 微信支付逻辑 System.out.println("微信支付,支付金额:" + command.getAmount()); } @Override public String getPayType() { return "WECHAT"; // 微信支付类型 } } @Component public class PayHandlerFactory { private final Map<String, PayHandler> handlerMap; @Autowired public PayHandlerFactory(List<PayHandler> handlerList) { handlerMap = new HashMap<>(); // 遍历 handlerList,将每个策略和支付类型关联起来 for (PayHandler handler : handlerList) { handlerMap.put(handler.getPayType(), handler); } } public PayHandler getHandler(String payType) { PayHandler handler = handlerMap.get(payType); if (handler == null) { throw new IllegalArgumentException("不支持的支付方式: " + payType); } return handler; } }

动态代理

代理类在运行期自动生成,无需手动实现

JDK动态代理(基于接口)
public interface OrderService { void createOrder(); } public class OrderServiceImpl implements OrderService { @Override public void createOrder() { System.out.println("👉 执行业务:创建订单"); } } import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class LogInvocationHandler implements InvocationHandler { private final Object target; public LogInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 方法前增强 System.out.println("🟢 方法前:记录日志 / 幂等校验 / 事务开始"); // 调用目标方法 Object result = method.invoke(target, args); // 方法后增强 System.out.println("🔵 方法后:提交事务 / 记录日志"); return result; } } import java.lang.reflect.Proxy; public class ProxyTest { public static void main(String[] args) { // 1️⃣ 目标对象 OrderService target = new OrderServiceImpl(); // 2️⃣ 创建代理对象 OrderService proxy = (OrderService) Proxy.newProxyInstance( target.getClass().getClassLoader(), // 类加载器 target.getClass().getInterfaces(), // 代理的接口 new LogInvocationHandler(target) // 方法拦截器 ); // 3️⃣ 调用代理方法 proxy.createOrder(); } }
CGLIB动态代理(基于继承)
二、目标类(⚠️ 没有接口) public class OrderService { public void createOrder() { System.out.println("👉 执行业务:创建订单"); } } 三、MethodInterceptor(核心拦截器) import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class LogMethodInterceptor implements MethodInterceptor { @Override public Object intercept( Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // 方法前增强 System.out.println("🟢 方法前:记录日志 / 事务开始"); // ⚠️ 调用父类方法(不是反射) Object result = proxy.invokeSuper(obj, args); // 方法后增强 System.out.println("🔵 方法后:提交事务"); return result; } } 📌 重点: invokeSuper() → 调用父类方法 不是 method.invoke()(性能更好) 四、创建代理对象(关键代码) import net.sf.cglib.proxy.Enhancer; public class CglibProxyTest { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); // 1️⃣ 设置父类(目标类) enhancer.setSuperclass(OrderService.class); // 2️⃣ 设置方法拦截器 enhancer.setCallback(new LogMethodInterceptor()); // 3️⃣ 创建代理对象(子类实例) OrderService proxy = (OrderService) enhancer.create(); // 4️⃣ 调用方法 proxy.createOrder(); } } 五、运行时 JVM 实际生成的类(核心理解) JVM 运行期生成的代理类类似: class OrderService$$EnhancerByCGLIB extends OrderService { @Override public void createOrder() { interceptor.intercept(...); } } 📌 这就是“基于继承”的直接体现 六、执行流程(一定要理解) proxy.createOrder() ↓ 子类重写方法 ↓ MethodInterceptor.intercept() ↓ invokeSuper() 调用父类 ↓ OrderService.createOrder()
Spring AOP

底层技术实现动态代理,上层通过切面思想和注解优化了实现

二、定义一个【幂等注解】 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Idempotent { /** * 幂等key的 SpEL 表达式 * 例如:#msg.orderId */ String key(); /** * 幂等超时时间(秒) */ long timeout() default 300; } 📌 关键点: SpEL 表达式 → 不侵入业务 不绑定 MQ、HTTP、RPC → 通用 三、RocketMQ 消费者(业务代码极简) @RocketMQMessageListener( topic = "ORDER_PAY_SUCCESS", consumerGroup = "order-consumer-group" ) @Component public class OrderPaySuccessConsumer implements RocketMQListener<OrderPayMsg> { @Override @Idempotent(key = "'ORDER_PAY_' + #msg.orderId") public void onMessage(OrderPayMsg msg) { // ✅ 这里不写任何幂等代码 orderService.handlePaySuccess(msg.getOrderId()); } } ✅ 你会发现: MQ 重试 重复投递 幂等控制 业务代码完全无感知 四、AOP 幂等切面(核心) @Aspect @Component public class IdempotentAspect { @Autowired private RedissonClient redissonClient; @Around("@annotation(idempotent)") public Object around(ProceedingJoinPoint pjp, Idempotent idempotent) throws Throwable { Method method = ((MethodSignature) pjp.getSignature()).getMethod(); // 1️⃣ 解析 SpEL,生成幂等 key String key = parseKey(idempotent.key(), method, pjp.getArgs()); String redisKey = "IDEMPOTENT:" + key; // 2️⃣ Redis 原子占位 RBucket<String> bucket = redissonClient.getBucket(redisKey); boolean success = bucket.trySet( "PROCESSING", idempotent.timeout(), TimeUnit.SECONDS ); if (!success) { // 🚫 幂等命中,直接返回 return null; } try { // 3️⃣ 执行业务逻辑 Object result = pjp.proceed(); // 4️⃣ 标记成功 bucket.set("SUCCESS", idempotent.timeout(), TimeUnit.SECONDS); return result; } catch (Exception e) { // ❗ 异常要删除 key,允许 MQ 重试 bucket.delete(); throw e; } } }

责任链模式

当执行业务逻辑前有很多条校验时采取责任链模式提升代码复用性和扩展性

定义一个责任链最高层接口,多个责任链模式接口,每个责任链模式接口多个实现类,把每个责任链模式的实现类根据定义好的Order排序存到List,再根据对应责任链模式存到Map

public interface AbstractChainHandler<T> extends Ordered { /** * 执行责任链逻辑 * * @param requestParam 责任链执行入参 */ void handler(T requestParam); /** * @return 责任链组件标识 */ String mark(); } public interface TrainPurchaseTicketChainFilter<T extends PurchaseTicketReqDTO> extends AbstractChainHandler<PurchaseTicketReqDTO> { @Override default String mark() { return TicketChainMarkEnum.TRAIN_PURCHASE_TICKET_FILTER.name(); } } @Component @RequiredArgsConstructor public class TrainPurchaseTicketParamNotNullChainHandler implements TrainPurchaseTicketChainFilter<PurchaseTicketReqDTO> { @Override public void handler(PurchaseTicketReqDTO requestParam) { if (StrUtil.isBlank(requestParam.getTrainId())) { throw new ClientException("列车标识不能为空"); } if (StrUtil.isBlank(requestParam.getDeparture())) { throw new ClientException("出发站点不能为空"); } if (StrUtil.isBlank(requestParam.getArrival())) { throw new ClientException("到达站点不能为空"); } if (CollUtil.isEmpty(requestParam.getPassengers())) { throw new ClientException("乘车人至少选择一位"); } for (PurchaseTicketPassengerDetailDTO each : requestParam.getPassengers()) { if (StrUtil.isBlank(each.getPassengerId())) { throw new ClientException("乘车人不能为空"); } if (Objects.isNull(each.getSeatType())) { throw new ClientException("座位类型不能为空"); } } } @Override public int getOrder() { return 0; } } @Component @RequiredArgsConstructor public class TrainPurchaseTicketParamVerifyChainHandler implements TrainPurchaseTicketChainFilter<PurchaseTicketReqDTO> { private final TrainMapper trainMapper; private final TrainStationMapper trainStationMapper; private final DistributedCache distributedCache; @Override public void handler(PurchaseTicketReqDTO requestParam) { // 查询会员购票车次是否存在,通过封装后安全的 Get 方法 TrainDO trainDO = distributedCache.safeGet( TRAIN_INFO + requestParam.getTrainId(), TrainDO.class, () -> trainMapper.selectById(requestParam.getTrainId()), ADVANCE_TICKET_DAY, TimeUnit.DAYS); if (Objects.isNull(trainDO)) { // 如果按照严谨逻辑,类似异常应该记录当前用户的 userid 并发送到风控中心 // 如果一段时间有过几次的异常,直接封号处理。下述异常同理 throw new ClientException("请检查车次是否存在"); } // TODO,当前列车数据并没有通过定时任务每天生成最新的,所以需要隔离这个拦截。后期定时生成数据后删除该判断 if (!EnvironmentUtil.isDevEnvironment()) { // 查询车次是否已经发售 if (new Date().before(trainDO.getSaleTime())) { throw new ClientException("列车车次暂未发售"); } // 查询车次是否在有效期内 if (new Date().after(trainDO.getDepartureTime())) { throw new ClientException("列车车次已出发禁止购票"); } } // 车站是否存在车次中,以及车站的顺序是否正确 String trainStationStopoverDetailStr = distributedCache.safeGet( TRAIN_STATION_STOPOVER_DETAIL + requestParam.getTrainId(), String.class, () -> { LambdaQueryWrapper<TrainStationDO> queryWrapper = Wrappers.lambdaQuery(TrainStationDO.class) .eq(TrainStationDO::getTrainId, requestParam.getTrainId()) .select(TrainStationDO::getDeparture); List<TrainStationDO> actualTrainStationList = trainStationMapper.selectList(queryWrapper); return CollUtil.isNotEmpty(actualTrainStationList) ? JSON.toJSONString(actualTrainStationList) : null; }, Index12306Constant.ADVANCE_TICKET_DAY, TimeUnit.DAYS ); List<TrainStationDO> trainDOList = JSON.parseArray(trainStationStopoverDetailStr, TrainStationDO.class); boolean validateStation = validateStation( trainDOList.stream().map(TrainStationDO::getDeparture).toList(), requestParam.getDeparture(), requestParam.getArrival() ); if (!validateStation) { throw new ClientException("列车车站数据错误"); } } @Override public int getOrder() { return 10; } public boolean validateStation(List<String> stationList, String startStation, String endStation) { int index1 = stationList.indexOf(startStation); int index2 = stationList.indexOf(endStation); if (index1 == -1 || index2 == -1) { return false; } return index2 >= index1; } } @Component @RequiredArgsConstructor public class TrainPurchaseTicketParamStockChainHandler implements TrainPurchaseTicketChainFilter<PurchaseTicketReqDTO> { private final SeatMarginCacheLoader seatMarginCacheLoader; private final DistributedCache distributedCache; @Override public void handler(PurchaseTicketReqDTO requestParam) { // 车次站点是否还有余票。如果用户提交多个乘车人非同一座位类型,拆分验证 String keySuffix = StrUtil.join("_", requestParam.getTrainId(), requestParam.getDeparture(), requestParam.getArrival()); StringRedisTemplate stringRedisTemplate = (StringRedisTemplate) distributedCache.getInstance(); List<PurchaseTicketPassengerDetailDTO> passengerDetails = requestParam.getPassengers(); Map<Integer, List<PurchaseTicketPassengerDetailDTO>> seatTypeMap = passengerDetails.stream() .collect(Collectors.groupingBy(PurchaseTicketPassengerDetailDTO::getSeatType)); seatTypeMap.forEach((seatType, passengerSeatDetails) -> { Object stockObj = stringRedisTemplate.opsForHash().get(TRAIN_STATION_REMAINING_TICKET + keySuffix, String.valueOf(seatType)); int stock = Optional.ofNullable(stockObj).map(each -> Integer.parseInt(each.toString())).orElseGet(() -> { Map<String, String> seatMarginMap = seatMarginCacheLoader.load(String.valueOf(requestParam.getTrainId()), String.valueOf(seatType), requestParam.getDeparture(), requestParam.getArrival()); return Optional.ofNullable(seatMarginMap.get(String.valueOf(seatType))).map(Integer::parseInt).orElse(0); }); if (stock >= passengerSeatDetails.size()) { return; } throw new ClientException("列车站点已无余票"); }); } @Override public int getOrder() { return 20; } } public final class AbstractChainContext<T> implements CommandLineRunner { private final Map<String, List<AbstractChainHandler>> abstractChainHandlerContainer = new HashMap<>(); /** * 责任链组件执行 * * @param mark 责任链组件标识 * @param requestParam 请求参数 */ public void handler(String mark, T requestParam) { List<AbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.get(mark); if (CollectionUtils.isEmpty(abstractChainHandlers)) { throw new RuntimeException(String.format("[%s] Chain of Responsibility ID is undefined.", mark)); } abstractChainHandlers.forEach(each -> each.handler(requestParam)); } @Override public void run(String... args) throws Exception { Map<String, AbstractChainHandler> chainFilterMap = ApplicationContextHolder .getBeansOfType(AbstractChainHandler.class); chainFilterMap.forEach((beanName, bean) -> { List<AbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.get(bean.mark()); if (CollectionUtils.isEmpty(abstractChainHandlers)) { abstractChainHandlers = new ArrayList(); } abstractChainHandlers.add(bean); List<AbstractChainHandler> actualAbstractChainHandlers = abstractChainHandlers.stream() .sorted(Comparator.comparing(Ordered::getOrder)) .collect(Collectors.toList()); abstractChainHandlerContainer.put(bean.mark(), actualAbstractChainHandlers); }); } }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/10 12:33:25

人体运动恢复技术入门:GVHMR项目的快速上手指南

人体运动恢复技术入门&#xff1a;GVHMR项目的快速上手指南 【免费下载链接】GVHMR Code for "GVHMR: World-Grounded Human Motion Recovery via Gravity-View Coordinates", Siggraph Asia 2024 项目地址: https://gitcode.com/gh_mirrors/gv/GVHMR 人体运动…

作者头像 李华
网站建设 2026/4/16 12:24:19

13、Python在网络协议与Windows NT管理中的应用

Python在网络协议与Windows NT管理中的应用 1. 基本网络协议的使用 Python与互联网几乎同时发展起来,早期二者主要运行在各种Unix系统上,因此Python对当今许多常用的互联网协议提供了出色的支持,并且这种支持也延续到了Windows平台。 1.1 HTTP与HTML 超文本传输协议(HT…

作者头像 李华
网站建设 2026/4/16 7:22:14

终极指南:使用X-editable与Select2打造专业级在线编辑体验

终极指南&#xff1a;使用X-editable与Select2打造专业级在线编辑体验 【免费下载链接】x-editable vitalets/x-editable: 是一个用于实现表单字段在线编辑的jQuery插件&#xff0c;可以方便地在Web应用中实现表单字段的在线编辑。适合对jQuery、表单编辑和想要实现表单在线编辑…

作者头像 李华
网站建设 2026/4/16 7:25:23

Oscar视觉语言模型终极指南:从零开始掌握多模态AI技术

Oscar视觉语言模型终极指南&#xff1a;从零开始掌握多模态AI技术 【免费下载链接】Oscar Oscar and VinVL 项目地址: https://gitcode.com/gh_mirrors/os/Oscar Oscar视觉语言模型是微软开发的一款强大的多模态人工智能框架&#xff0c;专门用于处理图像和文本的跨模态…

作者头像 李华
网站建设 2026/4/16 7:25:21

26、.NET与Windows Azure的SOA安全:认证、授权与访问控制

.NET与Windows Azure的SOA安全:认证、授权与访问控制 在当今数字化的时代,服务导向架构(SOA)的安全性至关重要。本文将深入探讨WCF(Windows Communication Foundation)的认证与授权机制、Windows Identity Foundation(WIF)以及Windows Azure的安全控制等方面的内容。 …

作者头像 李华
网站建设 2026/4/16 7:25:41

【花雕学编程】Arduino BLDC 之动态调整互补滤波系数

主要特点 自适应特性&#xff1a;能够依据电机运行的实际状况&#xff0c;自动调整互补滤波系数。在不同转速、负载等条件下&#xff0c;实时改变滤波特性&#xff0c;以更好地契合电机动态变化的需求。 精度提升&#xff1a;通过动态调整滤波系数&#xff0c;能够更精准地融合…

作者头像 李华