当前位置: 首页 > news >正文

java设计模式实战【策略模式+观察者模式+命令模式+组合模式,混合模式在支付系统中的应用】

引言

在代码开发的世界里,理论知识的重要性毋庸置疑,但实战经验往往才是知识的真正试金石。正所谓,“读万卷书不如行万里路”,理论的学习需要通过实践来验证和深化。设计模式作为软件开发中的重要理论,其真正的价值在于它们在解决实际问题时的应用。之前的一篇文章中,我们通过物流系统,引入了策略+工厂方法模式,感兴趣的读者可以去阅读Java设计模式实战:从If-Else到策略+工厂方法的演变,本文将再通过支付系统来展示策略模式+观察者模式+命令模式+组合模式的混合模式在实际开发中的应用。

本文不仅是对设计模式的理论讲解,更是一次深入实战的探索。无论你是一名经验丰富的开发者还是刚入行的新手,看一遍肯定记不住,请记得收藏本文,相信一定会为你在未来工作中,引入设计模式提供一份参考

目录

  1. 案例分析
    • 支付系统概述
    • 关键功能
    • 面临的挑战
  2. 初始代码
    • 定义Payment实体类
    • 定义PaymentSystemService接口
    • 定义PaymentSystemServiceImpl实现类
    • 模拟调用
  3. 初始代码存在的问题分析
  4. 引入策略模式
    • 策略模式介绍
    • 引入策略模式后的代码
    • 引入策略模式后存在的问题分析
  5. 引入观察者模式
    • 观察者模式介绍
    • 引入观察者模式后的代码
    • 引入观察者模式后存在的问题分析
  6. 引入命令+组合模式
    • 命令及组合模式介绍
    • 引入命令+组合模式后的代码
    • 引入命令+组合模式后的分析
  7. 混合模式设计的系统优势
  8. 写在最后

案例分析

支付系统概述

简单来说支付系统需要处理多种支付方式,还要与其他系统组件,比如风控、营销等系统进行交互,是比较复杂且难以设计的一类系统。我们就以支付系统为例,引入混合设计模式来优化

关键功能
  1. 多渠道支付处理:支持多种支付渠道,如信用卡、电子钱包、银行转账等。用户可以根据自己的偏好选择合适的支付方式
  2. 支付状态跟踪:需要跟踪和管理每笔交易的状态,确保交易的顺利完成
  3. 风控通知:在支付过程中,系统需要与风控等系统交互,确保交易的安全性
  4. 日志记录:系统应记录所有关键的支付信息,用于审计和故障排查
  5. 组合支付支持:系统应支持组合支付,即允许用户在一次交易中使用多种支付方式
面临的挑战
  1. 高耦合度:不同支付渠道的处理逻辑紧密耦合,使得系统难以适应新支付方式的添加或现有方式的修改
  2. 通知机制不灵活:支付完成后的通知机制(如风控通知和日志记录)固定且不易扩展,难以适应多变的业务需求
  3. 组合支付复杂性:支持组合支付(比如 余额+银行卡),增加了系统的复杂性,尤其是在处理多种支付方式的交互和状态管理时
  4. 维护和扩展困难:由于系统的复杂性和高耦合度,新功能的添加和现有功能的维护变得困难和风险较高

在接下来的部分中,我们将探讨如何通过引入策略模式、观察者模式和命令及组合模式的混合模式来解决这些挑战,提高支付系统的灵活性、可扩展性和可维护性

初始代码

①定义Payment实体类:

import java.math.BigDecimal;
import java.util.List;
import java.util.ArrayList;class Payment {String paymentType;BigDecimal amount;Payment(String paymentType, BigDecimal amount) {this.paymentType = paymentType;this.amount = amount;}
}

②定义PaymentSystemService接口:

import java.util.List;public interface PaymentSystemService {void processPayments(List<Payment> payments);
}

③定义PaymentSystemServiceImpl实现类:

public class PaymentSystemServiceImpl implements PaymentSystemService {@Overridepublic void processPayments(List<Payment> payments) {// 处理支付processPaymentMethod(payments);// 支付完成后的通知notifyRiskManagement(payments);// 上报埋点日志logTransactions(payments);}private void processPaymentMethod(List<Payment> payments) {for (Payment payment : payments) {switch (payment.paymentType) {case "CreditCard":System.out.println("Processing credit card payment: " + payment.amount);break;case "PayPal":System.out.println("Processing PayPal payment: " + payment.amount);break;// 其他支付方式...}}}// 通知风控private void notifyRiskManagement(List<Payment> payments) {System.out.println("Notifying risk management for payment.");}// 日志埋点private void logTransactions(List<Payment> payments) {for (Payment payment : payments) {System.out.println("Logging transaction: Payment type: " + payment.paymentType + ", Amount: " + payment.amount);}}
}

④模拟调用

public class Main {public static void main(String[] args) {PaymentSystemService paymentService = new PaymentSystemServiceImpl();// 示例:组合支付List<Payment> combinedPayments = new ArrayList<>();combinedPayments.add(new Payment("CreditCard", new BigDecimal("50.0")));combinedPayments.add(new Payment("PayPal", new BigDecimal("25.0")));paymentService.processPayments(combinedPayments);// 示例:单一支付// List<Payment> singlePayment = new ArrayList<>();// singlePayment.add(new Payment("CreditCard", new BigDecimal("75.0")));// paymentService.processPayments(singlePayment);}
}

初始代码存在的问题分析

在上述的初始实现中,PaymentSystemServiceImpl 类直接处理了所有的支付逻辑。这种实现方式存在几个主要问题:

  1. 高耦合度:支付逻辑直接与 PaymentSystemServiceImpl 类耦合,使得该类承担了过多的责任。每种支付方式的逻辑都集中在一个类中,违反了单一职责原则
  2. 扩展性差:添加或修改支付方式都需要修改 PaymentSystemServiceImpl 类,这违反了开闭原则
  3. 通知机制僵化:支付完成后的通知机制(如风控通知和日志记录)与支付逻辑紧密耦合,缺乏灵活性。难以适应不断变化的业务需求,必如需要增加新的通知类型或修改通知流程

为了解决这些问题,我们第一时间可以考虑引入策略模式来处理不同支付方式的逻辑,使得每种支付方式都有自己的策略类,解决这个主要问题

引入策略模式

策略模式介绍

策略模式是一种行为设计模式,它定义了一系列算法,并将每一个算法封装起来,使它们可以互换。策略模式让算法的变化独立于使用算法的客户

在支付系统中,我们可以定义一个支付策略接口,每种支付方式实现这个接口。PaymentSystemServiceImpl 类可以使用这些策略来处理不同的支付方式,而不是直接实现所有支付逻辑

引入策略模式后的代码

①定义策略接口PaymentStrategy以及具体的策略类CreditCardPaymentStrategy…:

import java.math.BigDecimal;/*** 定义支付策略的接口。*/
public interface PaymentStrategy {/*** 检查此策略是否适用于指定的支付类型。** @param paymentType 支付类型* @return 如果策略适用于该支付类型,则返回 true*/boolean appliesTo(String paymentType);/*** 处理支付。** @param amount 支付金额*/void processPayment(BigDecimal amount);
}/*** 信用卡支付策略。*/
public class CreditCardPaymentStrategy implements PaymentStrategy {@Overridepublic boolean appliesTo(String paymentType) {return "CreditCard".equals(paymentType);}@Overridepublic void processPayment(BigDecimal amount) {System.out.println("Processing credit card payment: " + amount);// 实现信用卡支付逻辑}
}/*** PayPal支付策略。*/
public class PayPalPaymentStrategy implements PaymentStrategy {@Overridepublic boolean appliesTo(String paymentType) {return "PayPal".equals(paymentType);}@Overridepublic void processPayment(BigDecimal amount) {System.out.println("Processing PayPal payment: " + amount);// 实现PayPal支付逻辑}
}

②修改PaymentSystemServiceImpl类:

public class PaymentSystemServiceImpl implements PaymentSystemService {private List<PaymentStrategy> paymentStrategies;public setPaymentStrategy(List<PaymentStrategy> paymentStrategies) {this.paymentStrategies = paymentStrategies;}@Overridepublic void processPayments(List<Payment> payments) {for (Payment payment : payments) {// 匹配策略PaymentStrategy strategy = paymentStrategies.stream().filter(s -> s.appliesTo(payment.paymentType)).findFirst().orElseThrow(() -> new IllegalArgumentException("No strategy found for payment type: " + payment.paymentType));strategy.processPayment(payment.amount);}// 支付完成后的通知notifyRiskManagement(payments);logTransactions(payments);}// ... notifyRiskManagement and logTransactions methods ...
}

③模拟调用

public class Main {public static void main(String[] args) {// 构造策略List<PaymentStrategy> strategies = new ArrayList<>();strategies.add(new CreditCardPaymentStrategy());strategies.add(new PayPalPaymentStrategy());// 注入策略PaymentSystemService paymentService = new PaymentSystemServiceImpl();paymentService.setPaymentStrategy(stategies);// 模拟组合支付场景List<Payment> payments = new ArrayList<>();payments.add(new Payment("CreditCard", new BigDecimal("50.0")));payments.add(new Payment("PayPal", new BigDecimal("25.0")));paymentService.processPayments(payments);}
}

引入策略模式后存在的问题分析

先看下当前代码的类图结构:
引入策略模式后的uml 类图
这个类图包括以下部分:

  • PaymentSystemService 接口,定义了处理支付的方法
  • PaymentSystemServiceImpl 类,实现了 PaymentSystemService 接口,并使用策略模式处理支付
  • PaymentStrategy 接口,定义了支付策略的方法
  • CreditCardPaymentStrategyPayPalPaymentStrategy 类,实现了 PaymentStrategy 接口,分别表示信用卡和PayPal的支付策略

存在的问题点:

  • 通知机制僵化:该问题依然存在,如果后续需要新增,比如财务记账通知,需要修改PaymentSystemService,显然违背了单一职责
  • 策略管理复杂性:尽管观察者模式优化了通知机制,但支付策略的管理(如策略的选择和执行)仍然是 PaymentSystemServiceImpl 类的责任,这可能导致策略管理复杂
  • 组合支付处理不足:当前的实现可能不足以优雅地处理组合支付场景,即在单次交易中使用多种支付方式。这需要更复杂的逻辑来协调不同支付方式的处理

因此我们考虑一个个问题依次解决,先引入观察者模式,以便解耦PaymentSystemServiceImpl类与通知,通知交给具体的观察者即可。这样可以用于实现更灵活的通知机制,后续可以动态添加或修改观察者

引入观察者模式

观察者模式介绍

观察者模式是一种行为设计模式,它定义了对象之间的一对多依赖关系,使得当一个对象改变状态时,所有依赖于它的对象都会得到通知并自动更新。这种模式非常适合实现事件处理系统。
在观察者模式中,存在两类主要角色:

  1. 主题(Subject):维护一系列观察者,提供用于注册和注销观察者的接口
  2. 观察者(Observer):提供一个更新接口,用于接收来自主题的通知

引入策略模式后的代码

import java.math.BigDecimal;
import java.util.List;
import java.util.ArrayList;// 观察者接口
interface Observer {void update(Payment payment);
}// 主题接口
interface Subject {// 注册观察者void registerObserver(Observer o);// 移除观察者void removeObserver(Observer o);// 通知观察者void notifyObservers(Payment payment);
}// 支付策略接口
interface PaymentStrategy {boolean appliesTo(String paymentType);void processPayment(BigDecimal amount);
}// 具体的支付策略实现
class CreditCardPaymentStrategy implements PaymentStrategy {@Overridepublic boolean appliesTo(String paymentType) {return "CreditCard".equals(paymentType);}@Overridepublic void processPayment(BigDecimal amount) {System.out.println("Processing credit card payment: " + amount);}
}class PayPalPaymentStrategy implements PaymentStrategy {@Overridepublic boolean appliesTo(String paymentType) {return "PayPal".equals(paymentType);}@Overridepublic void processPayment(BigDecimal amount) {System.out.println("Processing PayPal payment: " + amount);}
}// 支付服务实现类
class PaymentSystemServiceImpl implements PaymentSystemService, Subject {private List<Observer> observers = new ArrayList<>();private List<PaymentStrategy> paymentStrategies;public PaymentSystemServiceImpl(List<PaymentStrategy> paymentStrategies) {this.paymentStrategies = paymentStrategies;}@Overridepublic void processPayments(List<Payment> payments) {for (Payment payment : payments) {PaymentStrategy strategy = paymentStrategies.stream().filter(s -> s.appliesTo(payment.paymentType)).findFirst().orElseThrow(() -> new IllegalArgumentException("No strategy found for payment type: " + payment.paymentType));strategy.processPayment(payment.amount);notifyObservers(payment);}}@Overridepublic void registerObserver(Observer o) {observers.add(o);}@Overridepublic void removeObserver(Observer o) {observers.remove(o);}@Overridepublic void notifyObservers(Payment payment) {for (Observer observer : observers) {observer.update(payment);}}
}// 支付类
class Payment {String paymentType;BigDecimal amount;Payment(String paymentType, BigDecimal amount) {this.paymentType = paymentType;this.amount = amount;}
}// 风控系统观察者
class RiskManagementObserver implements Observer {@Overridepublic void update(Payment payment) {System.out.println("Risk Management notified for payment: " + payment.amount);// 实现风控逻辑notifyRiskManagement(payment);}private void notifyRiskManagement(Payment payment) {// 风控通知逻辑}
}// 日志系统观察者
class LoggingObserver implements Observer {@Overridepublic void update(Payment payment) {System.out.println("Logging payment transaction: " + payment.amount);// 实现日志记录逻辑logTransaction(payment);}private void logTransaction(Payment payment) {// 日志记录逻辑}
}// 主方法
public class Main {public static void main(String[] args) {List<PaymentStrategy> strategies = new ArrayList<>();strategies.add(new CreditCardPaymentStrategy());strategies.add(new PayPalPaymentStrategy());PaymentSystemServiceImpl paymentService = new PaymentSystemServiceImpl(strategies);paymentService.registerObserver(new RiskManagementObserver());paymentService.registerObserver(new LoggingObserver());List<Payment> payments = new ArrayList<>();payments.add(new Payment("CreditCard", new BigDecimal("50.0")));payments.add(new Payment("PayPal", new BigDecimal("25.0")));paymentService.processPayments(payments);}
}

引入观察者模式后存在的问题分析

引入观察者模式后的类图:
[引入观察者模式后的问题分析内容]
组合支付的时序流程图:
组合支付时序流程图

引入观察者模式后解决的问题

  • 解耦通知机制

  • 观察者模式将支付完成后的通知逻辑(如风控通知和日志记录)从 PaymentSystemServiceImpl 类中解耦出来。每个观察者负责处理特定的响应逻辑,降低了主类的复杂性

  • 提高灵活性和可扩展性

  • 通过观察者模式,可以轻松添加或移除观察者,无需修改主类的代码。这使得在支付系统中引入新的通知类型(如财务记账通知)变得更加简单

  • 更好地遵循单一职责原则

  • 观察者模式使得每个类(包括主类和观察者)都专注于单一的职责,提高了代码的可维护性

引入观察者模式后仍存在的问题

  • 策略管理复杂性:问题依然存在,尽管观察者模式优化了通知机制,但支付策略的管理(如策略的选择和执行)仍然是 PaymentSystemServiceImpl 类的责任,这可能导致策略管理复杂

  • 组合支付处理不足:问题依然存在,当前的实现可能不足以优雅地处理组合支付场景,即在单次交易中使用多种支付方式。这需要更复杂的逻辑来协调不同支付方式的处理

解决策略:

  • 对于第一个问题,之前有介绍过用工厂方法模式解决,感兴趣的读者可以去阅读Java设计模式实战:从If-Else到策略+工厂方法的演变,本篇文章我们换一种模式,用命令模式来解决(很多设计模式其实都可以相互替换)
  • 对于第二个问题,我们可以考虑引入组合模式。组合模式可以用于优雅地处理组合支付场景,允许将多个支付方式组合成一个支付请求。这样,我们可以将组合支付的逻辑从 PaymentSystemServiceImpl 类中分离出来,进一步提高系统的灵活性和可维护性

引入命令+组合模式

命令及组合模式介绍

  • 命令模式:适用于管理和封装支付策略的执行逻辑。可以将支付操作封装为命令对象,使得支付处理逻辑与执行逻辑分离,提高代码的可重用性和可维护性。有助于实现撤销(undo)和重做(redo)等操作,增加系统的灵活性
  • 组合模式:适用于处理组合支付场景,即在单次交易中使用多种支付方式。允许客户端以统一的方式处理单个支付组合支付,简化了客户端的使用。提高了代码的结构清晰度和可扩展性

引入命令+组合模式后的代码

import java.math.BigDecimal;
import java.util.List;
import java.util.ArrayList;// 观察者接口
interface Observer {void update(BigDecimal amount);
}// 主题接口
interface Subject {void registerObserver(Observer o);void removeObserver(Observer o);void notifyObservers(BigDecimal amount);
}// 命令接口
interface PaymentCommand {void execute();
}// 具体的支付命令
class ConcretePaymentCommand implements PaymentCommand {private PaymentStrategy strategy;private BigDecimal amount;private Subject subject;ConcretePaymentCommand(PaymentStrategy strategy, BigDecimal amount, Subject subject) {this.strategy = strategy;this.amount = amount;this.subject = subject;}@Overridepublic void execute() {strategy.processPayment(amount);subject.notifyObservers(amount);}
}// 支付策略接口
interface PaymentStrategy {void processPayment(BigDecimal amount);
}// 具体的支付策略
class CreditCardPaymentStrategy implements PaymentStrategy {@Overridepublic void processPayment(BigDecimal amount) {System.out.println("Processing credit card payment: " + amount);}
}class PayPalPaymentStrategy implements PaymentStrategy {@Overridepublic void processPayment(BigDecimal amount) {System.out.println("Processing PayPal payment: " + amount);}
}// 支付组件接口(组合模式)
interface PaymentComponent {void processPayment();
}// 单一支付(叶子节点)
class SinglePayment implements PaymentComponent {private PaymentCommand command;SinglePayment(PaymentCommand command) {this.command = command;}@Overridepublic void processPayment() {command.execute();}
}// 组合支付(复合节点)
class CompositePayment implements PaymentComponent {private List<PaymentComponent> payments = new ArrayList<>();void addPayment(PaymentComponent payment) {payments.add(payment);}@Overridepublic void processPayment() {for (PaymentComponent payment : payments) {payment.processPayment();}}
}// 支付服务实现(同时作为主题)
class PaymentSystemServiceImpl implements Subject {private List<Observer> observers = new ArrayList<>();@Overridepublic void registerObserver(Observer o) {observers.add(o);}@Overridepublic void removeObserver(Observer o) {observers.remove(o);}@Overridepublic void notifyObservers(BigDecimal amount) {for (Observer observer : observers) {observer.update(amount);}}void processPayments(PaymentComponent paymentComponent) {paymentComponent.processPayment();}
}// 观察者实现
class RiskManagementObserver implements Observer {@Overridepublic void update(BigDecimal amount) {System.out.println("Risk Management notified for payment: " + amount);}
}class LoggingObserver implements Observer {@Overridepublic void update(BigDecimal amount) {System.out.println("Logging payment transaction: " + amount);}
}// 主方法
public class Main {public static void main(String[] args) {PaymentSystemServiceImpl paymentService = new PaymentSystemServiceImpl();paymentService.registerObserver(new RiskManagementObserver());paymentService.registerObserver(new LoggingObserver());PaymentStrategy creditCardStrategy = new CreditCardPaymentStrategy();PaymentStrategy payPalStrategy = new PayPalPaymentStrategy();SinglePayment creditCardPayment = new SinglePayment(new ConcretePaymentCommand(creditCardStrategy, new BigDecimal("50.0"), paymentService));SinglePayment payPalPayment = new SinglePayment(new ConcretePaymentCommand(payPalStrategy, new BigDecimal("25.0"), paymentService));CompositePayment compositePayment = new CompositePayment();compositePayment.addPayment(creditCardPayment);compositePayment.addPayment(payPalPayment);paymentService.processPayments(compositePayment);}
}

引入命令+组合模式后的分析

现在完整的类图:
策略+观察者+命令+组合
这个类图包括以下部分:

  • Observer 和 Subject 接口,分别表示观察者和主题的基本结构
  • PaymentCommand和ConcretePaymentCommand 类,实现命令模式。 PaymentStrategy 接口及其具体实现类
  • CreditCardPaymentStrategy 和 PayPalPaymentStrategy,表示不同的支付策略
  • PaymentComponent 接口及其实现类 SinglePayment 和 CompositePayment,体现组合模式
  • PaymentSystemServiceImpl 类,实现了 Subject 接口,同时处理支付命令
  • RiskManagementObserver 和 LoggingObserver 类,作为观察者实现特定的通知逻辑

混合模式设计的系统优势

  1. 增强的灵活性和可扩展性
    • 策略模式允许动态更换支付逻辑,适应新的支付方式
    • 命令模式通过将请求封装为对象,提供了根据不同情况使用不同请求的灵活性
    • 组合模式使客户端能以统一方式处理单一支付和组合支付,简化客户端使用
  2. 解耦和模块化
    • 观察者模式将通知逻辑从主业务逻辑中解耦,简化了通知类型的添加和修改
    • 策略模式命令模式的应用进一步解耦了支付处理逻辑,增强了模块化
  3. 提高代码的可维护性
    • 模式的应用降低了系统的整体复杂性,使代码更清晰易维护
    • 系统的不同部分可以独立变化,减少了相互间的影响
  4. 更好地遵循软件设计原则
    • 混合模式设计遵循了单一职责原则、开放封闭原则等
    • 提高了系统的可测试性和可靠性

通过这种混合模式设计,支付系统不仅变得更加灵活和可扩展,而且更易于管理和维护。这为应对不断变化的业务需求和技术挑战提供了坚实的基础

写在最后

比起写代码,写文章确实很难,一方面时间精力有限,一方面难以直接将工作代码放在这里,只能自己去编写示例,难免会有疏漏,可能不是特别准确。但总体相信,一定可以给你带来一些思想上的启发。

通过混合使用策略模式、命令模式、组合模式和观察者模式,成功地构建了一个灵活、可扩展且易于维护的支付系统。这种设计不仅提高了系统的模块化和解耦,还优化了支付处理和通知机制,确保了代码的清晰性和可维护性。这些模式的结合展示了如何有效地应对复杂系统设计中的常见挑战,同时保持代码的整洁性与扩展性

希望这篇文章能够为你提供有价值的见解,并帮助你在未来的项目中应用这些设计模式。

我是程序员三毛,如果您觉得这篇文章对您有帮助,请不吝点赞、关注和收藏。您的支持是我不断前进的动力!

  • 程序员三毛

相关文章:

java设计模式实战【策略模式+观察者模式+命令模式+组合模式,混合模式在支付系统中的应用】

引言 在代码开发的世界里&#xff0c;理论知识的重要性毋庸置疑&#xff0c;但实战经验往往才是知识的真正试金石。正所谓&#xff0c;“读万卷书不如行万里路”&#xff0c;理论的学习需要通过实践来验证和深化。设计模式作为软件开发中的重要理论&#xff0c;其真正的价值在…...

小程序wx:if 和hidden的区别?

在小程序中&#xff0c;wx:if 和 hidden 是用于条件渲染的两种不同方式。 选择使用哪种方式取决于具体情况。如果条件变化频繁或节点包含复杂的子节点&#xff0c;可以考虑使用 wx:if 进行条件渲染&#xff1b;如果条件变化较少且节点结构简单&#xff0c;可以使用 hidden 控制…...

自动驾驶学习笔记(二十三)——车辆控制模型

#Apollo开发者# 学习课程的传送门如下&#xff0c;当您也准备学习自动驾驶时&#xff0c;可以和我一同前往&#xff1a; 《自动驾驶新人之旅》免费课程—> 传送门 《Apollo开放平台9.0专项技术公开课》免费报名—>传送门 文章目录 前言 运动学模型 动力学模型 总结…...

Linux Shell 015-文本双向覆盖重定向工具tee

Linux Shell 015-文本双向覆盖重定向工具tee 本节关键字&#xff1a;Linux、Bash Shell、文本双向覆盖重定向工具 相关指令&#xff1a;tee、echo、cat tee介绍 tee工具是从标准输入读取并写入到标准输出和文件&#xff0c;即&#xff1a;双向覆盖重定向&#xff08;屏幕输出…...

【PyQt】(自定义类)QIcon派生,更易用的纯色Icon

嫌Qt自带的icon太丑&#xff0c;自己写了一个&#xff0c;主要用于纯色图标的自由改色。 当然&#xff0c;图标素材得网上找。 Qt原生图标与现代图标对比&#xff1a; 没有对比就没有伤害 Qt图标 网络素材图标 自定义类XJQ_Icon&#xff1a; from PyQt5.QtGui import QIc…...

【mysql】数据处理格式化、转换、判断

数据处理 判断是否超时&#xff0c;时间是否大于当前时间计算分钟数时间格式化处理如果数值类型进行转换字符类型字符拼接case-when代替if-else判断数据空&#xff08;特殊&#xff1a;含空数据、空字符处理&#xff09; select /*判断是否超时&#xff0c;时间是否大于当前…...

深入探索Java中的UDP网络通信机制

在网络通信中&#xff0c;UDP&#xff08;User Datagram Protocol&#xff0c;用户数据报协议&#xff09;是一种无连接的协议&#xff0c;它在某些情况下比TCP更适合&#xff0c;尤其是在要求速度快、对数据准确性要求相对较低的场景下。本文将介绍如何使用Java进行UDP网络通信…...

List常见方法和遍历操作

List集合的特点 有序&#xff1a; 存和取的元素顺序一致有索引&#xff1a;可以通过索引操作元素可重复&#xff1a;存储的元素可以重复 List集合的特有方法 Collection的方法List都继承了List集合因为有索引&#xff0c;所以有了很多操作索引的方法 ublic static void main…...

【基础篇】一、认识JVM

文章目录 1、虚拟机2、Java虚拟机3、JVM的整体结构4、Java代码的执行流程5、JVM的三大功能6、JVM的分类7、JVM的生命周期 1、虚拟机 虚拟机&#xff0c;Virtual Machine&#xff0c;一台虚拟的计算机&#xff0c;用来执行虚拟计算机指令。分为&#xff1a; 系统虚拟机&#x…...

DrGraph原理示教 - OpenCV 4 功能 - 颜色空间

前言 前段时间&#xff0c;甲方提出明确需求&#xff0c;让把软件国产化。稍微研究了一下&#xff0c;那就转QT开发&#xff0c;顺便把以前的功能代码重写一遍。 至于在Ubuntu下折腾QT、OpenCV安装事宜&#xff0c;网上文章很多&#xff0c;照猫画虎即可。 这个过程&#xff0…...

听GPT 讲Rust源代码--src/tools(36)

File: rust/src/tools/clippy/clippy_lints/src/loops/empty_loop.rs 在Rust源代码中&#xff0c;empty_loop.rs文件位于src/tools/clippy/clippy_lints/src/loops/目录下&#xff0c;它的作用是实现并提供一个名为EMPTY_LOOP的Lint规则。Clippy是一个Rust的静态分析工具&#…...

学生数据可视化与分析工具 vue3+flask实现

目录 一、技术栈亮点 二、功能特点 三、应用场景 四、结语 学生数据可视化与分析工具介绍 在当今的教育领域&#xff0c;数据驱动的决策正变得越来越重要。为了满足学校、教师和学生对于数据深度洞察的需求&#xff0c;我们推出了一款基于Vue3和Flask编写的学生数据可视化…...

uni-app condition启动模式配置

锋哥原创的uni-app视频教程&#xff1a; 2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中..._哔哩哔哩_bilibili2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中...共计23条视频&#xff0c;包括&#xff1a;第1讲 uni…...

网大为卸任腾讯CXO;Midjourney 1 月训练视频模型;2023年马斯克赚了7700亿

投融资 • 2023 年大型科技公司在生成式 AI 初创企业上的投资远超风险投资集团• 恒信东方与无锡政府合作成立布局 MR/XR 技术及 3D 数字资产 AIGC 产业投资基金• 新公司法完善注册资本认缴登记制度• 网大为卸任腾讯CXO&#xff0c;曾促成南非MIH的投资• 宁波蔚孚科技完成数…...

据报道,微软的下一代 Surface 笔记本电脑将是其首款真正的“人工智能 PC”

明年&#xff0c;微软计划推出 Surface Laptop 6和 Surface Pro 10&#xff0c;这两款设备将提供 Arm 和 Intel 两种处理器选项。不愿意透露姓名的不透露姓名人士透露&#xff0c;这些新设备将引入先进的人工智能功能&#xff0c;包括配备下一代神经处理单元 (NPU)。据悉&#…...

Springer build pdf乱码

在textstudio中编辑时没有错误&#xff0c;在editor manager生成pdf时报错。 首先不要改源文件&#xff0c;着重看你的上传顺序&#xff1a; 将.tex文件&#xff0c;.bst文件&#xff0c;.cls文件&#xff0c;.bib文件, .bbl文件的类型&#xff0c;在editor manager中是Item。…...

k8s之kudeadm

kubeadm来快速的搭建一个k8s的集群&#xff1a; 二进制搭建适合大集群&#xff0c;50台以上主机 kubeadm更适合中小企业的业务集群 master&#xff1a;192.168.233.91 docker kubelet lubeadm kubectl flannel node1:192.168.233.92 docker kubelet lubeadm kubectl flannel…...

NModbus-一个C#的Modbus协议库实现

NModbus-一个基于C#实现的Modbus通信协议库 最近在学习C#的时候&#xff0c;因为之前做过环保设备时使用C做过环保设备采集使用到了Modbus协议&#xff0c;当时看了一下基于C语言开发的libmodbus库。所以特意搜索看了一下C#下有什么Modbus协议库&#xff0c;在Github上面找了一…...

Altium Designer20中遇到的问题和解决办法记录

最近二战考完研了&#xff0c;重新拾起之前学的一些项目&#xff0c;最近在优化以前话的四层PCB版的时候发现了在使用AD使碰到一些问题现在记录如下&#xff1a; 1.Altium Designer 中的 Clearance Constraint 错误如何修改 &#xff1a; 我遇到的报错如下&#xff1a;  这…...

flask web学习之flask与http(二)

文章目录 1. HTTP响应1.1 响应报文1.2 常见HTTP状态码1.3 在flask中如何生成响应1.3.1重定向1.3.2错误响应 1.4响应格式 在flask程序中&#xff0c;客户端发出的请求触发相应的视图函数&#xff0c;获取返回值会作为响应的主体&#xff0c;最后生成完整的响应&#xff0c;即响应…...

基于Python的电商手机数据可视化分析和推荐系统

1. 项目简介 本项目旨在通过Python技术栈对京东平台上的手机数据进行抓取、分析并构建一个简单的手机推荐系统。主要功能包括&#xff1a; 网络爬虫&#xff1a;从京东获取手机数据&#xff1b;数据分析&#xff1a;统计各厂商手机销售分布、市场占有率、价格区间和好评率&am…...

汽车制造厂批量使用成华制造弹簧平衡器

数年来&#xff0c;成华制造都在不断的向各行各界输出着自己的起重设备&#xff0c;与众多企业达成合作&#xff0c;不断供应优质产品。近些年&#xff0c;成华制造以其卓越的产品质量和高效的生产能力&#xff0c;成功实现了弹簧平衡器的大规模批量供应&#xff0c;为重庆数家…...

一语道破爬虫,来揭开爬虫面纱

目录 一、爬虫&#xff08;网络蜘蛛(Spider)&#xff09; 1.1、是什么&#xff1a; 1.2、学习的原因 1.3、用在地方&#xff1a; 1.4、是否合法&#xff1a; 1.5、后果 案例&#xff1a; 二、应用领域 三、Robots协议 四、抓包 4.1、浏览器抓包 4.2、抓包工具 常见…...

时序分解 | Matlab实现贝叶斯变化点检测与时间序列分解

时序分解 | Matlab实现贝叶斯变化点检测与时间序列分解 目录 时序分解 | Matlab实现贝叶斯变化点检测与时间序列分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现贝叶斯变化点检测与时间序列分解 1.Matlab实现贝叶斯变化点检测与时间序列分解&#xff0c;完…...

Python 操作 MySQL:使用 mysql-connector-python 操作 MySQL 数据库

大家好&#xff0c;我是水滴~~ 当涉及到使用 Python 操作 MySQL 数据库时&#xff0c;mysql-connector-python 库是一个强大而常用的选择。该库提供了与 MySQL 数据库的交互功能&#xff0c;使您能够执行各种数据库操作&#xff0c;如连接数据库、执行查询和插入数据等。在本文…...

虚拟化技术和云计算的关系

1、云计算底层就是虚拟化技术。 &#xff08;1&#xff09;常见的虚拟化技术&#xff1a;VMware&#xff08;闭源的&#xff0c;需要收费&#xff09;、XEN、KVM &#xff08;2&#xff09;大部分公司用的虚拟化方案&#xff1a;XEN、KVM 2、虚拟化的历史 &#xff08;1&am…...

【privateGPT】使用privateGPT训练您自己的LLM

了解如何在不向提供商公开您的私人数据的情况下训练您自己的语言模型 使用OpenAI的ChatGPT等公共人工智能服务的主要担忧之一是将您的私人数据暴露给提供商的风险。对于商业用途&#xff0c;这仍然是考虑采用人工智能技术的公司最大的担忧。 很多时候&#xff0c;你想创建自己…...

权威Scrum敏捷开发企业培训分享

课程简介 Scrum是目前运用最为广泛的敏捷开发方法&#xff0c;是一个轻量级的项目管理和产品研发管理框架。 这是一个两天的实训课程&#xff0c;面向研发管理者、项目经理、产品经理、研发团队等&#xff0c;旨在帮助学员全面系统地学习Scrum和敏捷开发, 帮助企业快速启动敏…...

面试要点,算法,数据结构等练习大全

有趣的算法&#xff0c;面试常常碰到&#xff0c;多种语言实现~ 1 从数组中找出两个数字使得他们的和是给定的数字 tags: #hash 使用一个散列&#xff0c;存储数字和他对应的索引。然后遍历数组&#xff0c;如果另一半在散列当中&#xff0c;那么返回 这两个数的索引&#x…...

八皇后问题(C语言)

了解题意 在一个8x8的棋盘上放置8个皇后&#xff0c;使得任何两个皇后都不能处于同一行、同一列或同一斜线上。问有多少种方法可以放置这8个皇后&#xff1f; 解决这个问题的目标是找到所有符合要求的皇后摆放方式&#xff0c;通常使用回溯算法来求解。回溯算法会尝试所有可能…...

利用网络教育系统构建个性化学习平台

在现代教育中&#xff0c;网络教育系统作为一种创新的学习方式&#xff0c;为学生提供了更加个性化和灵活的学习体验。在本文中&#xff0c;我们将通过简单的技术代码&#xff0c;演示如何构建一个基础的网络教育系统&#xff0c;为学生提供个性化的学习路径和资源。 1. 环境…...

滤波器opencv

在OpenCV中&#xff0c;滤波器用于对图像进行平滑、锐化、边缘检测等操作。以下是一些常用的滤波器及其在OpenCV中的Python代码示例&#xff1a; 均值滤波器&#xff08;平滑图像&#xff09;&#xff1a; import cv2 import numpy as np# 读取图像 image cv2.imread(path_t…...

使用 Docker Compose 部署 Halo 2.x 与 MySQL

使用 Docker Compose 部署 Halo 2.x 与 MySQL 本文主要介绍使用 Docker Compose 部署 Halo 2.x 和 MySQL&#xff0c; 主要针对小白。 有一定基础的&#xff0c; 可以直接去官网查看。 博主博客 https://blog.uso6.comhttps://blog.csdn.net/dxk539687357 一、Docker 与 Dock…...

openGauss学习笔记-179 openGauss 数据库运维-逻辑复制-发布订阅

文章目录 openGauss学习笔记-179 openGauss 数据库运维-逻辑复制-发布订阅179.1 发布179.2 订阅179.3 冲突处理179.4 限制179.5 架构179.6 监控179.7 安全性179.8 配置设置179.9 快速设置 openGauss学习笔记-179 openGauss 数据库运维-逻辑复制-发布订阅 发布和订阅基于逻辑复…...

2023十大编程语言及未来展望

2023十大编程语言及未来展望 1. 2023年十大编程语言排行榜2. 十大编程语言未来展望PythonCCJavaC#JavaScriptPHPVisual BasicSQLAssembly language 1. 2023年十大编程语言排行榜 TIOBE排行榜是根据互联网上有经验的程序员、课程和第三方厂商的数量&#xff0c;并使用搜索引擎&a…...

Docker启动各种服务

文章目录 1 启动MySQL2 启动maven&#xff0c;用于编译java程序3 容器内启动sshd&#xff0c;用于远程编码和调试 1 启动MySQL 守护方式运行一个容器&#xff1a; docker run --name mysql5.7 -e MYSQL_ROOT_PASSWORD123456 -p 3307:3306 -d mysql进入容器&#xff1a; dock…...

AndroidR集成三方Native服务组件

一、背景 该项目为海外欧盟市场版本,需集成三方IDS安全组件,进程运行时注入iptables指令至链表,检测网络运行状态,并收集异常日志并压缩打包成gz文件,提供给Android上层应用上报云端。 二、分析 1、将提供的组件包集成至系统vendor分区 /vendor/bin/idsLogd/vendor/li…...

C++连接数据库(DataBase)之加载外部依赖项

文章目录 在VS中进行配置一、 先找到VS的解决方案资源管理器&#xff1a;二、 找到“属性”&#xff0c;进行附加项配置三、 移植libmysql.dll目录 在VSCode中进行配置依赖文件的移动库文件的移动可能遇到的问题 重点&#xff01;&#xff01;&#xff01;&#xff01;&#xf…...

论文阅读——Slide-Transformer(cvpr2023)

Slide-Transformer: Hierarchical Vision Transformer with Local Self-Attention 一、分析 1、改进transformer的几个思路&#xff1a; &#xff08;1&#xff09;将全局感受野控制在较小区域&#xff0c;如&#xff1a;PVT&#xff0c;DAT&#xff0c;使用稀疏全局注意力来…...

【Flink-Kafka-To-Mysql】使用 Flink 实现 Kafka 数据写入 Mysql(根据对应操作类型进行增、删、改操作)

【Flink-Kafka-To-Mysql】使用 Flink 实现 Kafka 数据写入 Mysql&#xff08;根据对应操作类型进行增、删、改操作&#xff09; 1&#xff09;导入依赖2&#xff09;resources2.1.appconfig.yml2.2.application.properties2.3.log4j.properties2.4.log4j2.xml 3&#xff09;uti…...

SpringMVC学习与开发(四)

注&#xff1a;此为笔者学习狂神说SpringMVC的笔记&#xff0c;其中包含个人的笔记和理解&#xff0c;仅做学习笔记之用&#xff0c;更多详细资讯请出门左拐B站&#xff1a;狂神说!!! 11、Ajax初体验 1、伪造Ajax 结果&#xff1a;并未有xhr异步请求 <!DOCTYPE html> &…...

odoo17核心概念view7——listview总体框架分析

这是view系列的第七篇文章&#xff0c;今天主要介绍我们最常用的list视图。 1、先看list_view,这是主文件 /** odoo-module */import { registry } from "web/core/registry"; import { RelationalModel } from "web/model/relational_model/relational_mode…...

大创项目推荐 深度学习交通车辆流量分析 - 目标检测与跟踪 - python opencv

文章目录 0 前言1 课题背景2 实现效果3 DeepSORT车辆跟踪3.1 Deep SORT多目标跟踪算法3.2 算法流程 4 YOLOV5算法4.1 网络架构图4.2 输入端4.3 基准网络4.4 Neck网络4.5 Head输出层 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; *…...

数字图像处理——亚像素边缘的轮廓提取

像素 像素是图像处理中的基本单位&#xff0c;一个像素是图像中最小的离散化单位&#xff0c;具有特定的位置和颜色信息。在数字图像中&#xff0c;每个像素都有一个特定的坐标&#xff0c;通常以行和列的形式表示。每个像素的颜色信息可以通过不同的表示方式&#xff0c;如灰…...

【六袆 - Framework】vue3入门;vue框架的特点矩阵列举;Vue.js 工作原理

vue框架的特点 Vue.js的特点展开叙述Vue.js的工作原理展开叙述 官方文档&#xff1a; https://cn.vuejs.org/guide/introduction.html Vue.js的特点 ┌────────────────────┬────────────────────────────────────…...

GO学习记录 —— 创建一个GO项目

文章目录 前言一、项目介绍二、目录介绍三、创建过程1.引入Gin框架、创建main2.加载配置文件3.连接MySQL、redis4.创建结构体5.错误处理、返回响应处理 前言 代码地址 下载地址&#xff1a;https://github.com/Lee-ZiMu/Golang-Init.git 一、项目介绍 1、使用Gin框架来创建项…...

C语言中的goto语句:使用、争议与最佳实践

各位少年&#xff1a; 引言&#xff1a; 在C语言编程中&#xff0c;goto语句是一个历史悠久且颇具争议的控制流结构。作为无条件跳转指令&#xff0c;它允许程序执行从当前点直接跳转到同一函数内的任意位置&#xff0c;由一个标签&#xff08;label&#xff09;来指定目标。尽…...

wpf-动态设置组件【按钮为例】样式

文章速览 解决方案具体实现Converter 部分创建样式Binding样式 坚持记录实属不易&#xff0c;希望友善多金的码友能够随手点一个赞。 共同创建氛围更加良好的开发者社区&#xff01; 谢谢~ 解决方案 创建一个Converter&#xff0c;返回对应的style实现对应的修改 创建多个样式…...

40道MyBatis面试题带答案(很全)

1. 什么是MyBatis &#xff08;1&#xff09;Mybatis是一个半ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;它内部封装了JDBC&#xff0c;开发时只需要关注SQL语句本身&#xff0c;不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。程序员直接…...

python:PyCharm更改.PyCharm配置文件夹存储位置

关联账号文章&#xff1a;另外的账号 在启动 PyCharm 后选择 Help -> Edit Custom Properties 的选项&#xff0c;弹出&#xff1a; 选择 Create &#xff0c;之后在文件中添加配置文件新的存储位置即可&#xff0c;例如&#xff1a; idea.config.pathD:/Program Files/.Py…...