Java设计模式:使用责任链模式和状态模式优化‘审批流程‘

Java设计模式:使用责任链模式和状态模式优化审批流程

    • 摘要
    • 引言
  • 需求
  • 流程图
    • 正文内容
      • 📐 基本概念介绍
  • 功能实现
  • 示例1:
      • 设计模式:责任链模式
      • 方法:
      • 好处:
  • 示例2:
      • 设计模式:责任链模式
      • 方法和操作流程:
      • 好处:
  • 示例3:
      • 设计模式:状态模式
      • 方法和操作流程:
      • 好处:
  • 总结
      • 责任链模式
      • 状态模式

在这里插入图片描述

博主 默语带您 Go to New World.
个人主页—— 默语 的博客👦🏻
《java 面试题大全》
《java 专栏》
🍩惟余辈才疏学浅,临摹之作或有不妥之处,还请读者海涵指正。☕🍭
《MYSQL从入门到精通》数据库是开发者必会基础之一~
🪁 吾期望此文有资助于尔,即使粗浅难及深广,亦备添少许微薄之助。苟未尽善尽美,敬请批评指正,以资改进。!💻⌨


Java设计模式:使用责任链模式和状态模式优化审批流程

摘要

在现代软件开发过程中,动态审核流程是确保数据质量和流程合规性的关键环节。本文将深入探讨一种链式处理模式,通过详实的代码示例和理论分析,展示如何高效构建一个灵活的审核流程。关键词:动态审核流程,链式处理模式,Java实现。

引言

在多用户环境下,如何高效且安全地管理和审核流程成为一个常见挑战。链式处理模式提供了一种优雅的解决方案,使得每个审核环节可以独立处理,同时保持整体流程的连贯性和扩展性。

需求

目前项目开发中遇到这样一个处理流程;
比如a发布–>b用户审核(审核过下一步不过打回)–>c用户审核(审核过下一步不过打回)–>发布成功(大家都能看到这个)

流程图

下面是简易的业务流程图

正文内容

📐 基本概念介绍

链式处理模式(Chain of Responsibility)是一种常用的设计模式,通过将请求的发送者和接收者解耦,让多个对象都有机会处理这个请求。在本案例中,我们将使用Java语言演示一个简单的发布审核流程,其中包含多个审核阶段。

功能实现

该功能有多种实现方式,下面给出3个简单的示例

示例1:

下面这段Java代码实现了一个简单的责任链模式(Chain of Responsibility Pattern)。责任链模式是一种行为设计模式,允许多个对象处理一个请求,或者将这些对象连成一条链。请求在这条链上传递,直到一个对象处理它为止。下面是对这段代码使用的设计模式、方法及其好处的详细解析:

设计模式:责任链模式

  1. 处理器接口(Handler)

    • 这个接口定义了一个 processRequest 方法,用于处理请求并返回响应。所有的具体处理器都需要实现这个接口。
  2. 具体处理器(HandlerA 和 HandlerB)

    • 这些类实现了 Handler 接口。每个处理器在接收到请求后,根据输入决定是否自己处理请求或将其传递给链中的下一个处理器。
    • 每个处理器类中包含一个 nextHandler 成员,它指向链中的下一个处理器。
  3. 请求(Request)和响应(Response)类

    • 这些类封装请求数据和响应数据。请求类包含请求内容,响应类包含响应内容和对内容的设置方法。

方法:

  • 请求和响应的创建与管理

    • 请求和响应对象在程序中通过各自的类创建,并在处理过程中被传递和修改。
  • 处理请求

    • HandlerAHandlerBprocessRequest 方法中,请求被检查和处理。处理器根据用户的输入(“approve” 或 “reject”)来决定是自己完成处理还是传递给下一个处理器。
  • 链的建立

    • main 方法中,创建处理器对象并通过 setNextHandler 方法设置它们的顺序。这种方式构建了处理器的责任链。

好处:

  • 低耦合性

    • 责任链模式降低了请求的发送者和接收者之间的耦合。处理器只需关注自己的职责范围,不必知道请求的全局处理流程。
  • 增强了灵活性

    • 可以在运行时动态地改变链中的成员或调整它们的顺序,从而增加新的处理逻辑或修改现有逻辑。
  • 简化了对象之间的连接

    • 每个对象只需保持一个指向其后继者的引用,而不是所有的潜在处理者,这简化了对象间的连接。
  • 分散了请求处理

    • 请求可以被多个对象处理,每个处理者处理它专门负责的部分,这有助于分散责任,使系统更加灵活和可扩展。

此设计模式非常适合于处理那些可能由多个不同对象处理的请求,每个对象处理它能处理的部分,不能处理的部分传递给链中的下一个对象。这在很多需要多级审批的系统中非常实用。

package com.example.sjms;
import java.util.Scanner; // 导入需要使用的Scanner类public class celms {// 定义请求类static  class Request {private String content; // 请求内容// 请求类构造函数public Request(String content) {this.content = content; // 初始化请求内容}// 获取请求内容的方法public String getContent() {return content;}}// 定义响应类static   class Response {private String content; // 响应内容// 响应类构造函数public Response(String content) {this.content = content; // 初始化响应内容}// 获取响应内容的方法public String getContent() {return content;}// 设置响应内容的方法public void setContent(String content) {this.content = content;}}// 定义处理器接口interface Handler {Response processRequest(Request request); // 处理请求的方法}// 具体处理器Astatic  class HandlerA implements Handler {private Handler nextHandler; // 下一个处理器对象// 实现处理请求的方法@Overridepublic Response processRequest(Request request) {System.out.println("正在处理请求,处理器A: " + request.getContent());try (Scanner scanner = new Scanner(System.in)) {System.out.println("用户审核(输入 'approve' 或 'reject'):");String input = scanner.nextLine().trim();// 判断用户输入,决定是否通过或者传递给下一个处理器if (input.equalsIgnoreCase("approve")) {return (nextHandler != null) ? nextHandler.processRequest(request) : new Response("发布成功");} else {return new Response("被驳回");}} catch (Exception ex) {// 捕捉异常并返回处理中出现错误return new Response("处理中出现错误");}}// 设置下一个处理器的方法public void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}}// 具体处理器Bstatic  class HandlerB implements Handler {private Handler nextHandler; // 下一个处理器对象// 实现处理请求的方法@Overridepublic Response processRequest(Request request) {try (Scanner scanner = new Scanner(System.in)) {System.out.println("用户审核(输入 'approve' 或 'reject'):");String input = scanner.nextLine().trim();// 判断用户输入,决定是否通过或者传递给下一个处理器if (input.equalsIgnoreCase("approve")) {return (nextHandler != null) ? nextHandler.processRequest(request) : new Response("发布成功");} else {return new Response("被驳回");}} catch (Exception ex) {// 捕捉异常并返回处理中出现错误return new Response("处理中出现错误");}}// 设置下一个处理器的方法public void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}}public static void main(String[] args) {// 创建处理器A和B对象HandlerA handlerA = new HandlerA();HandlerB handlerB = new HandlerB();// 设置处理器A的下一个处理器为处理器BhandlerA.setNextHandler(handlerB);// 创建一个请求对象Request request = new Request("待发布内容");// 处理请求并获取响应Response response = handlerA.processRequest(request);
/*** 创建请求对象:* Request request = new Request("待发布内容"); 这行代码创建了一个请求对象,传入的参数是待发布的内容字符串 "待发布内容"。这个请求对象将在处理过程中被传递给处理器,并沿着责任链向下传递。* 处理请求并获取响应:* Response response = handlerA.processRequest(request); 这行代码调用了处理器A的 processRequest 方法,并将之前创建的请求对象 request 作为参数传递进去。处理器A将根据请求内容执行相应的操作,并可能将请求传递给下一个处理器。最终,这个方法返回一个响应对象,表示处理的结果。在这里,我们将得到的响应对象赋值给 response 变量,以便后续使用。*/// 输出最终结果System.out.println("最终结果: " + response.getContent());}}

示例2:

这段代码也是一个实现了责任链模式(Chain of Responsibility Pattern)的示例,不过它更加简化并集中了一些功能。这里的处理器(HandlerA 和 HandlerB)被设计为按顺序处理一个请求对象,根据用户的输入决定是否批准请求或将其拒绝。每个处理器在用户输入批准后可以将请求传递给下一个处理器,如果没有下一个处理器或用户输入拒绝,则结束请求的处理。下面是对这段代码的具体分析:

设计模式:责任链模式

  1. 处理器接口(Handler):

    • 定义了 processRequest 方法,这是责任链中每个节点共有的处理请求的接口。
  2. 具体处理器(HandlerA 和 HandlerB):

    • 实现了 Handler 接口,每个处理器根据输入决定是否处理请求或将其传递给链中的下一个处理器。
    • 处理器A负责模拟“B用户”的审核流程,处理器B负责模拟“C用户”的审核流程。
  3. 请求(Request)和响应(Response)类:

    • 这些类封装请求和响应的数据,提供了基本的构造函数和访问方法。

方法和操作流程:

  • 构建责任链:

    • main 方法中,处理器对象被创建并通过 setNextHandler 方法相互链接,形成责任链。
  • 处理请求:

    • 请求对象被创建并传递给责任链的第一个处理器(HandlerA)。处理器根据扫描器输入决定是否批准请求或传递给下一个处理器。
  • 动态决策和处理:

    • 每个处理器在接到请求后通过用户输入动态决定是结束处理还是继续传递请求至责任链的下一个节点。

好处:

  • 灵活性:

    • 责任链模式允许动态地添加或修改处理链,每个处理器独立处理它的职责范围。
  • 解耦:

    • 请求的发起者和请求的处理者解耦,提高了系统各部分的独立性。
  • 扩展性:

    • 新的处理器可以很容易地加入到现有的链中,或者从链中移除,而不会影响其他处理器。
  • 维护性:

    • 责任链模式使得维护和理解代码更加容易,因为每个处理器只关注自己责任范围内的逻辑。

这种模式适用于处理那些可能需要多个对象共同参与的请求,如不同级别的权限审批。在实际应用中,这种模式可以用于工作流管理、事件处理系统等场景。

package com.example.sjms;import java.util.Scanner;/*** Chain of Responsibility 模式演示* 客户端类包含所有代码,采用责任链模式实现审核流程控制*/
public class celms2 {/*** 请求类*/static class Request {private String content;public Request(String content) {this.content = content;}public String getContent() {return content;}}/*** 响应类*/static class Response {private String content;public Response(String content) {this.content = content;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}}// 定义处理器接口interface Handler {Response processRequest(Request request);}// 具体处理器Astatic class HandlerA implements Handler {private Handler nextHandler;@Overridepublic Response processRequest(Request request) {System.out.println("处理器A正在处理请求:" + request.getContent());// 模拟B用户审核Scanner scanner = new Scanner(System.in);System.out.println("B用户审核(输入 'approve' 或 'reject'):");String input = scanner.nextLine().trim();if (input.equalsIgnoreCase("approve")) {return (nextHandler != null) ? nextHandler.processRequest(request) : new Response("发布成功");} else {return new Response("被驳回");}}public void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}}// 具体处理器Bstatic class HandlerB implements Handler {private Handler nextHandler;@Overridepublic Response processRequest(Request request) {System.out.println("处理器B正在处理请求:" + request.getContent());// 模拟C用户审核Scanner scanner = new Scanner(System.in);System.out.println("C用户审核(输入 'approve' 或 'reject'):");String input = scanner.nextLine().trim();if (input.equalsIgnoreCase("approve")) {return (nextHandler != null) ? nextHandler.processRequest(request) : new Response("发布成功");} else {return new Response("被驳回");}}public void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}}// 客户端类public static void main(String[] args) {// 创建处理器A和B对象HandlerA handlerA = new HandlerA();HandlerB handlerB = new HandlerB();// 设置处理器A的下一个处理器为处理器BhandlerA.setNextHandler(handlerB);// 创建一个请求对象Request request = new Request("待审核内容");// 处理请求并获取响应Response response = handlerA.processRequest(request);// 输出最终结果System.out.println("最终结果: " + response.getContent());}
}

示例3:

这段代码是一个典型的状态模式(State Pattern)的应用。状态模式是一种行为设计模式,允许一个对象在其内部状态改变时改变它的行为。这是通过将每个状态逻辑封装到对应的类中来实现的。在这段代码中,每个状态类都实现了一个共同的接口 ApprovalState,这样不同的状态可以以不同的方式处理相同的行为。

设计模式:状态模式

  1. 状态接口(ApprovalState)
    • 定义了必须实现的 processApproval 方法,该方法接受一个请求对象和审批流程上下文作为参数。
  2. 具体状态(PendingState, ApprovedState, RejectedState)
    • 每个类实现 ApprovalState 接口,提供了处理审批请求的具体实现。根据用户输入,这些状态类可以改变审批流程的当前状态。
  3. 审批流程上下文(ApprovalProcess)
    • 维护一个对当前状态对象的引用,允许状态对象在其内部状态改变时请求改变其行为。
    • 提供 setCurrentState 方法来改变当前状态,以及 processApproval 方法来开始或继续审批流程。

方法和操作流程:

  • 状态转换
    • PendingState 中,根据用户输入,状态可能转换为 ApprovedStateRejectedState。如果输入错误,将递归调用自身直到获得有效输入。
  • 处理审批
    • 每个状态对象根据其逻辑处理来自请求的输入,并可以决定是否结束流程或者将流程移至另一个状态。

好处:

  • 封装状态变化
    • 状态模式允许状态转换的逻辑封装于状态对象内部,使得状态转换显式且集中。
  • 减少条件分支
    • 状态模式减少了操作中条件语句的使用。状态对象代替了这些条件语句,每个状态都有相应的行为。
  • 增加可扩展性
    • 新增状态只需添加新的状态类并调整状态转换逻辑,而无需修改现有状态类代码,这使得系统更易于扩展。
  • 增强代码组织
    • 通过分离不同状态的行为,代码更为清晰和易于管理。

这种模式特别适合用于那些对象的行为依赖于其状态的场景,且状态的改变需要引起行为的改变。在这个例子中,它帮助管理了复杂的审批流程,每个状态都有明确的行为和转换逻辑。这使得维护和理解审批流程变得更容易,尤其是在涉及多个审批阶段和条件时。

package com.example.sjms;
import java.util.Scanner;public class celms3 {/*** 审批状态接口*/interface ApprovalState {void processApproval(Request request, ApprovalProcess process);}/*** 待审批状态*/static class PendingState implements ApprovalState {@Overridepublic void processApproval(Request request, ApprovalProcess process) {System.out.println("当前状态:待审批");System.out.println("内容:" + request.getContent());System.out.println("等待审批中...");// 模拟审批人员操作Scanner scanner = new Scanner(System.in);System.out.println("请输入审批结果(通过/拒绝):");String input = scanner.nextLine().trim();if (input.equalsIgnoreCase("通过")) {process.setCurrentState(new ApprovedState());} else if (input.equalsIgnoreCase("拒绝")) {process.setCurrentState(new RejectedState());} else {System.out.println("输入错误,请重新输入!");processApproval(request, process); // 递归调用,直到输入正确为止}}}/*** 通过状态*/static class ApprovedState implements ApprovalState {@Overridepublic void processApproval(Request request, ApprovalProcess process) {System.out.println("当前状态:已通过");System.out.println("内容:" + request.getContent());System.out.println("审批已通过,流程结束。");// 在审批通过后输出结果System.out.println("审批结果:" + request.getContent() + " 已通过。");}}/*** 拒绝状态*/static class RejectedState implements ApprovalState {@Overridepublic void processApproval(Request request, ApprovalProcess process) {System.out.println("当前状态:已拒绝");System.out.println("内容:" + request.getContent());System.out.println("审批已拒绝,流程结束。");// 在审批拒绝后输出结果System.out.println("审批结果:" + request.getContent() + " 已拒绝。");}}/*** 审批流程上下文*/static class ApprovalProcess {private ApprovalState currentState;public ApprovalProcess() {this.currentState = new PendingState(); // 初始状态为待审批}public void setCurrentState(ApprovalState currentState) {this.currentState = currentState;}public void processApproval(Request request) {currentState.processApproval(request, this); // 委托给当前状态处理审批流程}}/*** 请求类*/static class Request {private String content;public Request(String content) {this.content = content;}public String getContent() {return content;}}/*** 客户端类*/public static void main(String[] args) {ApprovalProcess process = new ApprovalProcess(); // 创建审批流程对象Request request = new Request("待审核内容"); // 创建请求对象// 处理请求,初始状态为待审批process.processApproval(request);// 输出结果System.out.println("审批流程结束。");}
}

本文中,我们分析了三个不同的Java代码示例,每个示例都实现了一种设计模式:责任链模式和状态模式。以下是对这些代码的详细分析和各自的总结:

总结

责任链模式

在前两个示例中,责任链模式被用来处理一个请求的审批流程。在这种模式中,多个对象(处理器)按顺序接收并处理请求,直到其中一个能处理该请求为止。每个处理器决定它是否能处理该请求或者是否将其传递给链中的下一个处理器。

关键特点包括:

  • 低耦合性:处理器只需关注自己的职责范围,不必知道请求的全局处理流程。
  • 灵活性:可以在运行时动态地改变链中的成员或调整它们的顺序,从而增加新的处理逻辑或修改现有逻辑。
  • 分散处理:请求可以被多个对象处理,每个处理者处理它能处理的部分。

状态模式

第三个示例展示了状态模式,其中审批流程的不同状态被封装在不同的状态对象中。状态模式允许对象在其内部状态改变时改变它的行为,这是通过将每个状态逻辑封装到对应的类中来实现的。

关键特点包括:

  • 封装状态变化:状态模式允许状态转换的逻辑封装于状态对象内部,使得状态转换显式且集中。
  • 减少条件分支:状态对象代替了操作中的条件语句,每个状态都有相应的行为。
  • 增加可扩展性:新增状态只需添加新的状态类并调整状态转换逻辑,而无需修改现有状态类代码。

这些设计模式各有其优势和适用场景。责任链模式适用于处理那些可能由多个不同对象处理的请求,特别是在处理流程中需要多级审批的系统中非常实用。而状态模式则适合于管理那些对象行为依赖于其状态的场景,它通过对状态的封装,简化了状态管理和行为变更,提高了系统的灵活性和可维护性。在实际应用中,根据系统的需求选择合适的设计模式,可以有效提升代码的可管理性和扩展性。

在这里插入图片描述


🪁🍁 希望本文能够给您带来一定的帮助🌸文章粗浅,敬请批评指正!🍁🐥

如对本文内容有任何疑问、建议或意见,请联系作者,作者将尽力回复并改进📓;(联系微信:Solitudemind )

点击下方名片,加入IT技术核心学习团队。一起探索科技的未来,共同成长。

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

【canvas】前端创造的图片粒子动画效果:HTML5 Canvas 技术详解

前端创造的图片粒子动画效果:HTML5 Canvas 技术详解 我们将深入探讨如何通过 HTML5 的 Canvas 功能,将上传的图片转换成引人入胜的粒子动画效果。这种效果将图片分解成小粒子,并在用户与它们交互时产生动态变化。我们将分步骤详细解析代码&a…

EasyRecovery数据恢复软件2025永久免费电脑版下载

EasyRecovery数据恢复软件是一款业界知名的数据恢复工具,它凭借强大的恢复能力和广泛的数据兼容性,帮助用户从各种存储设备中恢复丢失或删除的数据。以下是关于EasyRecovery数据恢复软件的详细介绍。 EasyRecovery绿色破解下载网盘链接: https://pan.ba…

自动驾驶行业源代码防泄漏解决方案

行业背景: 随着新一代信息通信及人工智能技术的快速发展,汽车作为这些新技术应用的重要载体,正在加速向智能化和网联化转型,以自动驾驶研发为主业的企业也越来越多,如何保障自己研发的算法、模型、系统不被研发人员离…

Linux入门攻坚——20、systemd、(sysvinit、upstart重温)

再一次讲到Linux系统启动流程: POST --> Boot Sequence --> Bootloader(grub) --> kernel initramfs(initrd) --> rootfs --> /sbin/init 对于init,即系统内核加载完毕后(加载kernel和切换根文件系统)运行…

STM32H750外设ADC之开始和结束数据转换功能

目录 概述 1 开始转换 1.1 使能ADSTART 1.2 使能JADSTART 1.3 ADSTART 通过硬件清零 2 转换时序 3 停止正在进行的转换( ADSTP、 JADSTP) 3.1 停止转换功能实现 3.2 停止转换流程图 概述 本文主要讲述了STM32H750外设ADC之开始和结束数据转换…

CentOS8/RHEL8 root密码破解

我们知道root是CentOS8/RHEL8系统的管理员用户,一般情况下,我们是不会把其密码忘记的,如果万一忘记了,如果破解root密码呢,今天就为大家详细讲讲。 1.CentOS8/RHEL8 root密码破解 1.默认安装及默认配置情况下&#x…

实践遥感场景目标检测,基于YOLOv8全系列【n/s/m/l/x】参数模型开发构建遥感场景下MSTAR数据基础上的目标检测识别系统

遥感相关的实践在我们前面的系列博文中也有相关的一些实践,基于MASTAR数据集开发构建对应的目标检测系统在前文也有一些介绍,感兴趣的话可以自行移步阅读即可: 《基于YOLOv7开发构建MSTAR雷达影像目标检测系统》 《基于yolov5n的轻量级MSTA…

前端开发攻略---用原生JS在网页中也能实现语音识别

1、语音识别的过程 语音识别涉及三个过程:首先,需要设备的麦克风接收这段语音;其次,语音识别服务器会根据一系列语法 (基本上,语法是你希望在具体的应用中能够识别出来的词汇) 来检查这段语音;最后&#xf…

Git操作与异常处理

文章目录 常用操作1、代码拉取2、代码提交3、暂存区状态4、提交代码5、推送远程仓库 异常处理【1】报错信息:Cannot pull into a repository with state: MERGING【2】报错信息:You have not concluded your merge (MERGE_HEAD exists)【3】报错信息&…

【网络编程】网络编程概念 | TCP和UDP的区别 | UDP数据报套接字编程 | Socket

文章目录 网络编程一、什么是网络编程1.TCP和UDP的区别 二、UDP数据报套接字编程DatagramSocketDatagramPacket回显服务器(echo server) 网络编程 一、什么是网络编程 通过网络,让两个主机之间能够进行通信。基于通信来完成一定的功能。 ​…

2.7设计模式——Proxy 代理模式(结构型)

意图 为其它对象提供一种代理以控制这个对象的访问。 结构 Proxy保存一个引用使得代理可以访问实体;提供一个与Subject的接口相同的接口,使代理可以用来替代实体;控制实体的存取,并可能负责创建和删除它;其他功能依赖…

[实验]Keil 4下仿真三星2440A芯片的汇编及CPIO控制实验

一、安装Keil uVision4 (详细安装过程忽略) 点击finish完成安装 二、新建项目,导入项目文件 选择对应的芯片,此处我们选择三星的S3C2440A,点击OK 在Source Group 1处右键,点击Add Files to "Sourcce Group 1’…将下图…

Linux之ebpf(1)基础使用

Linux之ebpf(1)基础使用 Author: Once Day Date: 2024年4月20日 一位热衷于Linux学习和开发的菜鸟,试图谱写一场冒险之旅,也许终点只是一场白日梦… 漫漫长路,有人对你微笑过嘛… 全系列文章可以参考专栏:Linux基础知识_Once-D…

非对称渐开线齿轮学习笔记分享

最近有小伙伴遇到了非对称渐开线齿轮的加工问题,花了些时间学习了解一下,下面是总结的学习笔记,有兴趣的朋友可以瞅瞅: 目录: 为什么要采用非对称? 非对称有什么优点? 非对称齿形如何加工? 非对称齿轮怎么测量? 非对称齿轮建模 为什么要采用非对称? 现在的传动要求…

关于浏览器360导航无法更改

当前环境场景: 浏览器:Microsoft Edge 版本 121.0.2277.106 (正式版本) (64 位) 系统:Windows 11 家庭中文版 23H2 问题描述 首先出现这种情况会让我们非常的气愤但是又束手无策,看到这个页面简直就恨的牙根痒痒,但是…

14.MMD导入Blender及贴图步骤

MMD导出.abc文件 在MMD十周年桥版本导入一个人物模型,这里导入仆人 注意MMD的路径不能有中文 点击上面的MMDBridge 设定 第一个选择blender by 第二个选择实行 这里是选择帧数范围和帧率 帧率一定要是30,不然后面可能会出问题 点击文件导出视频…

C/C++开发,opencv-ml库学习,支持向量机(SVM)应用

目录 一、OpenCV支持向量机(SVM)模块 1.1 openCV的机器学习库 1.2 SVM(支持向量机)模块 1.3 支持向量机(SVM)应用步骤 二、支持向量机(SVM)应用示例 2.1 训练及验证数据获取 2…

Gin+WebSocket实战——在线聊天室WebSocketDemo详细使用教程

文章目录 仓库地址项目简介如何使用 仓库地址 Github:https://github.com/palp1tate/WebsocketDemo 欢迎star!😎 项目简介 利用 GinWebSocket 实现的在线聊天室Demo项目,支持加入/离开聊天室广播、给其他用户发送消息等。 如何…

STL——List常用接口模拟实现及其使用

认识list list的介绍 list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。 list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素…

系统思考—心智模式

如果你总是做你过去一直做的事,你将永远得到你一直得到的结果。——托尼罗宾斯 在1980年代早期,美国汽车公司的高层主管定期前往日本参观,想要了解日本汽车行业为何能超越美国。这些主管返回后常说:“他们没有让我们看到真正的工…