2024050702-重学 Java 设计模式《实战状态模式》

重学 Java 设计模式:实战状态模式「模拟系统营销活动,状态流程审核发布上线场景」

一、前言

写好代码三个关键点

如果把写代码想象成家里的软装,你肯定会想到家里需要有一个非常不错格局最好是南北通透的,买回来的家具最好是品牌保证质量的,之后呢是大小合适,不能摆放完了看着别扭。那么把这一过程抽象成写代码就是需要三个核心的关键点;架构(房间的格局)、命名(品牌和质量)、注释(尺寸大小说明书),只有这三个点都做好才能完成出一套赏心悦目的

平原走码🐎易放难收

上学期间你写了多少代码?上班一年你能写多少代码?回家自己学习写了多少代码?个人素养的技术栈地基都是一块一块砖码出来的,写的越广越深,根基就越牢固。当根基牢固了以后在再上层建设就变得迎刃而解了,也更容易建设了。往往最难的就是一层一层阶段的突破,突破就像破壳一样,也像夯实地基,短时间看不到成绩,也看不出高度。但以后谁能走的稳,就靠着默默的沉淀。

技术传承的重要性

可能是现在时间节奏太快,一个需求下来恨不得当天就上线(这个需求很简单,怎么实现我不管,明天上线!),导致团队的人都很慌很急很累很崩溃,最终反反复复的人员更替,项目在这个过程中也交接了N次,文档不全、代码混乱、错综复杂,谁在后面接手也都只能修修补补,就像烂尾楼。这个没有传承、没有沉淀的项目,很难跟随业务的发展。最终!根基不牢,一地鸡毛。

二、开发环境

  1. JDK 1.8
  2. Idea + Maven
  3. 涉及工程三个,可以通过关注公众号bugstack虫洞栈,回复源码下载获取(打开获取的链接,找到序号18)
工程描述
itstack-demo-design-19-00场景模拟工程;模拟营销活动操作服务(查询、审核)
itstack-demo-design-19-01使用一坨代码实现业务需求
itstack-demo-design-19-02通过设计模式优化改造代码,产生对比性从而学习

三、状态模式介绍

状态模式,图片来自 refactoringguru.cn

  • 图片来自:https://refactoringguru.cn/design-patterns/state

状态模式描述的是一个行为下的多种状态变更,比如我们最常见的一个网站的页面,在你登录与不登录下展示的内容是略有差异的(不登录不能展示个人信息),而这种登录不登录就是我们通过改变状态,而让整个行为发生了变化。

收音机&放音机&磁带机

至少80后、90后的小伙伴基本都用过这种磁带放音机(可能没有这个好看),它的上面是一排按钮,当放入磁带后,通过上面的按钮就可以让放音机播放磁带上的内容(listen to 英语听力考试),而且有些按钮是互斥的,当在某个状态下才可以按另外的按钮(这在设计模式里也是一个关键的点)。

四、案例场景模拟

在这里插入图片描述

在本案例中我们模拟营销活动审核状态流转场景(一个活动的上线是多个层级审核上线的)

在上图中也可以看到我们的流程节点中包括了各个状态到下一个状态扭转的关联条件,比如;审核通过才能到活动中,而不能从编辑中直接到活动中,而这些状态的转变就是我们要完成的场景处理。

大部分程序员基本都开发过类似的业务场景,需要对活动或者一些配置需要审核后才能对外发布,而这个审核的过程往往会随着系统的重要程度而设立多级控制,来保证一个活动可以安全上线,避免造成资损。

当然有时候会用到一些审批流的过程配置,也是非常方便开发类似的流程的,也可以在配置中设定某个节点的审批人员。但这不是我们主要体现的点,在本案例中我们主要是模拟学习对一个活动的多个状态节点的审核控制。

1. 场景模拟工程

itstack-demo-design-19-00
└── src└── main└── java└── org.itstack.demo.design├── ActivityInfo.java├── Status.java└── ActivityService.java
  • 在这个模拟工程里我们提供了三个类,包括;状态枚举(Status)、活动对象(ActivityInfo)、活动服务(ActivityService),三个服务类。
  • 接下来我们就分别介绍三个类包括的内容。

2. 代码实现

2.1 基本活动信息
public class ActivityInfo {private String activityId;    // 活动IDprivate String activityName;  // 活动名称private Enum<Status> status;  // 活动状态private Date beginTime;       // 开始时间private Date endTime;         // 结束时间// ...get/set
}  
  • 一些基本的活动信息;活动ID、活动名称、活动状态、开始时间、结束时间。
2.2 活动枚举状态
public enum Status {// 1创建编辑、2待审核、3审核通过(任务扫描成活动中)、4审核拒绝(可以撤审到编辑状态)、5活动中、6活动关闭、7活动开启(任务扫描成活动中)Editing, Check, Pass, Refuse, Doing, Close, Open}
  • 活动的枚举;1创建编辑、2待审核、3审核通过(任务扫描成活动中)、4审核拒绝(可以撤审到编辑状态)、5活动中、6活动关闭、7活动开启(任务扫描成活动中)
2.3 活动服务接口
public class ActivityService {private static Map<String, Enum<Status>> statusMap = new ConcurrentHashMap<String, Enum<Status>>();public static void init(String activityId, Enum<Status> status) {// 模拟查询活动信息ActivityInfo activityInfo = new ActivityInfo();activityInfo.setActivityId(activityId);activityInfo.setActivityName("早起学习打卡领奖活动");activityInfo.setStatus(status);activityInfo.setBeginTime(new Date());activityInfo.setEndTime(new Date());statusMap.put(activityId, status);}/*** 查询活动信息** @param activityId 活动ID* @return 查询结果*/public static ActivityInfo queryActivityInfo(String activityId) {// 模拟查询活动信息ActivityInfo activityInfo = new ActivityInfo();activityInfo.setActivityId(activityId);activityInfo.setActivityName("早起学习打卡领奖活动");activityInfo.setStatus(statusMap.get(activityId));activityInfo.setBeginTime(new Date());activityInfo.setEndTime(new Date());return activityInfo;}/*** 查询活动状态** @param activityId 活动ID* @return 查询结果*/public static Enum<Status> queryActivityStatus(String activityId) {return statusMap.get(activityId);}/*** 执行状态变更** @param activityId   活动ID* @param beforeStatus 变更前状态* @param afterStatus  变更后状态 b*/public static synchronized void execStatus(String activityId, Enum<Status> beforeStatus, Enum<Status> afterStatus) {if (!beforeStatus.equals(statusMap.get(activityId))) return;statusMap.put(activityId, afterStatus);}}
  • 在这个静态类中提供了活动的查询和状态变更接口;queryActivityInfoqueryActivityStatusexecStatus
  • 同时使用Map的结构来记录活动ID和状态变化信息,另外还有init方法来初始化活动数据。实际的开发中这类信息基本都是从数据库或者Redis中获取。

五、用一坨坨代码实现

这里我们先使用最粗暴的方式来实现功能

对于这样各种状态的变更,最让我们直接想到的就是使用ifelse进行判断处理。每一个状态可以流转到下一个什么状态,都可以使用嵌套的if实现。

1. 工程结构

itstack-demo-design-19-01
└── src└── main└── java└── org.itstack.demo.design├── ActivityExecStatusController.java└── Result.java
  • 整个实现的工程结构比较简单,只包括了两个类;ActivityExecStatusControllerResult,一个是处理流程状态,另外一个是返回的对象。

2. 代码实现

public class ActivityExecStatusController {/*** 活动状态变更* 1. 编辑中 -> 提审、关闭* 2. 审核通过 -> 拒绝、关闭、活动中* 3. 审核拒绝 -> 撤审、关闭* 4. 活动中 -> 关闭* 5. 活动关闭 -> 开启* 6. 活动开启 -> 关闭** @param activityId   活动ID* @param beforeStatus 变更前状态* @param afterStatus  变更后状态* @return 返回结果*/public Result execStatus(String activityId, Enum<Status> beforeStatus, Enum<Status> afterStatus) {// 1. 编辑中 -> 提审、关闭if (Status.Editing.equals(beforeStatus)) {if (Status.Check.equals(afterStatus) || Status.Close.equals(afterStatus)) {ActivityService.execStatus(activityId, beforeStatus, afterStatus);return new Result("0000", "变更状态成功");} else {return new Result("0001", "变更状态拒绝");}}// 2. 审核通过 -> 拒绝、关闭、活动中if (Status.Pass.equals(beforeStatus)) {if (Status.Refuse.equals(afterStatus) || Status.Doing.equals(afterStatus) || Status.Close.equals(afterStatus)) {ActivityService.execStatus(activityId, beforeStatus, afterStatus);return new Result("0000", "变更状态成功");} else {return new Result("0001", "变更状态拒绝");}}// 3. 审核拒绝 -> 撤审、关闭if (Status.Refuse.equals(beforeStatus)) {if (Status.Editing.equals(afterStatus) || Status.Close.equals(afterStatus)) {ActivityService.execStatus(activityId, beforeStatus, afterStatus);return new Result("0000", "变更状态成功");} else {return new Result("0001", "变更状态拒绝");}}// 4. 活动中 -> 关闭if (Status.Doing.equals(beforeStatus)) {if (Status.Close.equals(afterStatus)) {ActivityService.execStatus(activityId, beforeStatus, afterStatus);return new Result("0000", "变更状态成功");} else {return new Result("0001", "变更状态拒绝");}}// 5. 活动关闭 -> 开启if (Status.Close.equals(beforeStatus)) {if (Status.Open.equals(afterStatus)) {ActivityService.execStatus(activityId, beforeStatus, afterStatus);return new Result("0000", "变更状态成功");} else {return new Result("0001", "变更状态拒绝");}}// 6. 活动开启 -> 关闭if (Status.Open.equals(beforeStatus)) {if (Status.Close.equals(afterStatus)) {ActivityService.execStatus(activityId, beforeStatus, afterStatus);return new Result("0000", "变更状态成功");} else {return new Result("0001", "变更状态拒绝");}}return new Result("0001", "非可处理的活动状态变更");}}
  • 这里我们只需要看一下代码实现的结构即可。从上到下是一整篇的ifelse,基本这也是大部分初级程序员的开发方式。
  • 这样的面向过程式开发方式,对于不需要改动代码,也不需要二次迭代的,还是可以使用的(但基本不可能不迭代)。而且随着状态和需求变化,会越来越难以维护,后面的人也不好看懂并且很容易填充其他的流程进去。越来越乱就是从点滴开始的

3. 测试验证

3.1 编写测试类
@Test
public void test() {// 初始化数据String activityId = "100001";ActivityService.init(activityId, Status.Editing);  ActivityExecStatusController activityExecStatusController = new ActivityExecStatusController();Result resultRefuse = activityExecStatusController.execStatus(activityId, Status.Editing, Status.Refuse); logger.info("测试结果(编辑中To审核拒绝):{}", JSON.toJSONString(resultRefuse));                           Result resultCheck = activityExecStatusController.execStatus(activityId, Status.Editing, Status.Check);logger.info("测试结果(编辑中To提交审核):{}", JSON.toJSONString(resultCheck));
}
  • 我们的测试代码包括了两个功能的验证,一个是从编辑中审核拒绝,另外一个是从编辑中到提交审核
  • 因为从我们的场景流程中可以看到,编辑中的活动是不能直接到审核拒绝的,这中间还需要提审
3.2 测试结果
23:24:30.774 [main] INFO  org.itstack.demo.design.test.ApiTest - 测试结果(编辑中To审核拒绝){"code":"0001","info":"变更状态拒绝"}
23:24:30.778 [main] INFO  org.itstack.demo.design.test.ApiTest - 测试结果(编辑中To提交审核){"code":"0000","info":"变更状态成功"}Process finished with exit code 0
  • 从测试结果和我们的状态流程的流转中可以看到,是符合测试结果预期的。除了不好维护外,这样的开发过程还是蛮快的,但不建议这么搞!

六、状态模式重构代码

接下来使用状态模式来进行代码优化,也算是一次很小的重构。

重构的重点往往是处理掉ifelse,而想处理掉ifelse基本离不开接口抽象类,另外还需要重新改造代码结构。

1. 工程结构

itstack-demo-design-19-02
└── src└── main└── java└── org.itstack.demo.design├── event│    ├── CheckState.java│    └── CloseState.java│    └── DoingState.java│    └── EditingState.java│    └── OpenState.java│    └── PassState.java│    └── RefuseState.java├── Result.java├── State.java└── StateHandler.java

状态模式模型结构

状态模式模型结构

  • 以上是状态模式的整个工程结构模型,State是一个抽象类,定义了各种操作接口(提审、审核、拒审等)。
  • 右侧的不同颜色状态与我们场景模拟中的颜色保持一致,是各种状态流程流转的实现操作。这里的实现有一个关键点就是每一种状态到下一个状态,都分配到各个实现方法中控制,也就不需要if语言进行判断了。
  • 最后是StateHandler对状态流程的统一处理,里面提供Map结构的各项服务接口调用,也就避免了使用if判断各项状态转变的流程。

2. 代码实现

2.1 定义状态抽象类
public abstract class State {/*** 活动提审** @param activityId    活动ID* @param currentStatus 当前状态* @return 执行结果*/public abstract Result arraignment(String activityId, Enum<Status> currentStatus);/*** 审核通过** @param activityId    活动ID* @param currentStatus 当前状态* @return 执行结果*/public abstract Result checkPass(String activityId, Enum<Status> currentStatus);/*** 审核拒绝** @param activityId    活动ID* @param currentStatus 当前状态* @return 执行结果*/public abstract Result checkRefuse(String activityId, Enum<Status> currentStatus);/*** 撤审撤销** @param activityId    活动ID* @param currentStatus 当前状态* @return 执行结果*/public abstract Result checkRevoke(String activityId, Enum<Status> currentStatus);/*** 活动关闭** @param activityId    活动ID* @param currentStatus 当前状态* @return 执行结果*/public abstract Result close(String activityId, Enum<Status> currentStatus);/*** 活动开启** @param activityId    活动ID* @param currentStatus 当前状态* @return 执行结果*/public abstract Result open(String activityId, Enum<Status> currentStatus);/*** 活动执行** @param activityId    活动ID* @param currentStatus 当前状态* @return 执行结果*/public abstract Result doing(String activityId, Enum<Status> currentStatus);}
  • 在整个接口中提供了各项状态流转服务的接口,例如;活动提审、审核通过、审核拒绝、撤审撤销等7个方法。
  • 在这些方法中所有的入参都是一样的,activityId(活动ID)、currentStatus(当前状态),只有他们的具体实现是不同的。
2.2 部分状态流转实现

编辑

public class EditingState extends State {public Result arraignment(String activityId, Enum<Status> currentStatus) {ActivityService.execStatus(activityId, currentStatus, Status.Check);return new Result("0000", "活动提审成功");}public Result checkPass(String activityId, Enum<Status> currentStatus) {return new Result("0001", "编辑中不可审核通过");}public Result checkRefuse(String activityId, Enum<Status> currentStatus) {return new Result("0001", "编辑中不可审核拒绝");}@Overridepublic Result checkRevoke(String activityId, Enum<Status> currentStatus) {return new Result("0001", "编辑中不可撤销审核");}public Result close(String activityId, Enum<Status> currentStatus) {ActivityService.execStatus(activityId, currentStatus, Status.Close);return new Result("0000", "活动关闭成功");}public Result open(String activityId, Enum<Status> currentStatus) {return new Result("0001", "非关闭活动不可开启");}public Result doing(String activityId, Enum<Status> currentStatus) {return new Result("0001", "编辑中活动不可执行活动中变更");}}

提审

public class CheckState extends State {public Result arraignment(String activityId, Enum<Status> currentStatus) {return new Result("0001", "待审核状态不可重复提审");}public Result checkPass(String activityId, Enum<Status> currentStatus) {ActivityService.execStatus(activityId, currentStatus, Status.Pass);return new Result("0000", "活动审核通过完成");}public Result checkRefuse(String activityId, Enum<Status> currentStatus) {ActivityService.execStatus(activityId, currentStatus, Status.Refuse);return new Result("0000", "活动审核拒绝完成");}@Overridepublic Result checkRevoke(String activityId, Enum<Status> currentStatus) {ActivityService.execStatus(activityId, currentStatus, Status.Editing);return new Result("0000", "活动审核撤销回到编辑中");}public Result close(String activityId, Enum<Status> currentStatus) {ActivityService.execStatus(activityId, currentStatus, Status.Close);return new Result("0000", "活动审核关闭完成");}public Result open(String activityId, Enum<Status> currentStatus) {return new Result("0001", "非关闭活动不可开启");}public Result doing(String activityId, Enum<Status> currentStatus) {return new Result("0001", "待审核活动不可执行活动中变更");}}
  • 这里提供了两个具体实现类的内容,编辑状态和提审状态。
  • 例如在这两个实现类中,checkRefuse这个方法对于不同的类中有不同的实现,也就是不同状态下能做的下一步流转操作已经可以在每一个方法中具体控制了。
  • 其他5个类的操作是类似的具体就不在这里演示了,大部分都是重复代码。可以通过源码进行学习理解。
2.3 状态处理服务
public class StateHandler {private Map<Enum<Status>, State> stateMap = new ConcurrentHashMap<Enum<Status>, State>();public StateHandler() {stateMap.put(Status.Check, new CheckState());     // 待审核stateMap.put(Status.Close, new CloseState());     // 已关闭stateMap.put(Status.Doing, new DoingState());     // 活动中stateMap.put(Status.Editing, new EditingState()); // 编辑中stateMap.put(Status.Open, new OpenState());       // 已开启stateMap.put(Status.Pass, new PassState());       // 审核通过stateMap.put(Status.Refuse, new RefuseState());   // 审核拒绝}public Result arraignment(String activityId, Enum<Status> currentStatus) {return stateMap.get(currentStatus).arraignment(activityId, currentStatus);}public Result checkPass(String activityId, Enum<Status> currentStatus) {return stateMap.get(currentStatus).checkPass(activityId, currentStatus);}public Result checkRefuse(String activityId, Enum<Status> currentStatus) {return stateMap.get(currentStatus).checkRefuse(activityId, currentStatus);}public Result checkRevoke(String activityId, Enum<Status> currentStatus) {return stateMap.get(currentStatus).checkRevoke(activityId, currentStatus);}public Result close(String activityId, Enum<Status> currentStatus) {return stateMap.get(currentStatus).close(activityId, currentStatus);}public Result open(String activityId, Enum<Status> currentStatus) {return stateMap.get(currentStatus).open(activityId, currentStatus);}public Result doing(String activityId, Enum<Status> currentStatus) {return stateMap.get(currentStatus).doing(activityId, currentStatus);}}
  • 这是对状态服务的统一控制中心,可以看到在构造函数中提供了所有状态和实现的具体关联,放到Map数据结构中。
  • 同时提供了不同名称的接口操作类,让外部调用方可以更加容易的使用此项功能接口,而不需要像在itstack-demo-design-19-01例子中还得传两个状态来判断。

3. 测试验证

3.1 编写测试类(Editing2Arraignment)
@Test
public void test_Editing2Arraignment() {String activityId = "100001";ActivityService.init(activityId, Status.Editing);StateHandler stateHandler = new StateHandler();Result result = stateHandler.arraignment(activityId, Status.Editing);logger.info("测试结果(编辑中To提审活动):{}", JSON.toJSONString(result));logger.info("活动信息:{} 状态:{}", JSON.toJSONString(ActivityService.queryActivityInfo(activityId)), JSON.toJSONString(ActivityService.queryActivityInfo(activityId).getStatus()));
}

测试结果

23:59:20.883 [main] INFO  org.itstack.demo.design.test.ApiTest - 测试结果(编辑中To提审活动){"code":"0000","info":"活动提审成功"}
23:59:20.907 [main] INFO  org.itstack.demo.design.test.ApiTest - 活动信息:{"activityId":"100001","activityName":"早起学习打卡领奖活动","beginTime":1593694760892,"endTime":1593694760892,"status":"Check"} 状态:"Check"Process finished with exit code 0
  • 测试编辑中To提审活动,的状态流转。
3.2 编写测试类(Editing2Open)
@Test
public void test_Editing2Open() {String activityId = "100001";ActivityService.init(activityId, Status.Editing);StateHandler stateHandler = new StateHandler();Result result = stateHandler.open(activityId, Status.Editing);logger.info("测试结果(编辑中To开启活动):{}", JSON.toJSONString(result));logger.info("活动信息:{} 状态:{}", JSON.toJSONString(ActivityService.queryActivityInfo(activityId)), JSON.toJSONString(ActivityService.queryActivityInfo(activityId).getStatus()));
}

测试结果

23:59:36.904 [main] INFO  org.itstack.demo.design.test.ApiTest - 测试结果(编辑中To开启活动){"code":"0001","info":"非关闭活动不可开启"}
23:59:36.914 [main] INFO  org.itstack.demo.design.test.ApiTest - 活动信息:{"activityId":"100001","activityName":"早起学习打卡领奖活动","beginTime":1593694776907,"endTime":1593694776907,"status":"Editing"} 状态:"Editing"Process finished with exit code 0
  • 测试编辑中To开启活动,的状态流转。
3.3 编写测试类(Refuse2Doing)
@Test
public void test_Refuse2Doing() {String activityId = "100001";ActivityService.init(activityId, Status.Refuse);StateHandler stateHandler = new StateHandler();Result result = stateHandler.doing(activityId, Status.Refuse);logger.info("测试结果(拒绝To活动中):{}", JSON.toJSONString(result));logger.info("活动信息:{} 状态:{}", JSON.toJSONString(ActivityService.queryActivityInfo(activityId)), JSON.toJSONString(ActivityService.queryActivityInfo(activityId).getStatus()));
}

测试结果

23:59:46.339 [main] INFO  org.itstack.demo.design.test.ApiTest - 测试结果(拒绝To活动中){"code":"0001","info":"审核拒绝不可执行活动为进行中"}
23:59:46.352 [main] INFO  org.itstack.demo.design.test.ApiTest - 活动信息:{"activityId":"100001","activityName":"早起学习打卡领奖活动","beginTime":1593694786342,"endTime":1593694786342,"status":"Refuse"} 状态:"Refuse"Process finished with exit code 0
  • 测试拒绝To活动中,的状态流转。
3.4 编写测试类(Refuse2Revoke)
@Test
public void test_Refuse2Revoke() {String activityId = "100001";ActivityService.init(activityId, Status.Refuse);StateHandler stateHandler = new StateHandler();Result result = stateHandler.checkRevoke(activityId, Status.Refuse);logger.info("测试结果(拒绝To撤审):{}", JSON.toJSONString(result));logger.info("活动信息:{} 状态:{}", JSON.toJSONString(ActivityService.queryActivityInfo(activityId)), JSON.toJSONString(ActivityService.queryActivityInfo(activityId).getStatus()));
}

测试结果

23:59:50.197 [main] INFO  org.itstack.demo.design.test.ApiTest - 测试结果(拒绝To撤审){"code":"0000","info":"撤销审核完成"}
23:59:50.208 [main] INFO  org.itstack.demo.design.test.ApiTest - 活动信息:{"activityId":"100001","activityName":"早起学习打卡领奖活动","beginTime":1593694810201,"endTime":1593694810201,"status":"Editing"} 状态:"Editing"Process finished with exit code 0
  • 测试测试结果(拒绝To撤审),的状态流转。

  • 综上以上四个测试类分别模拟了不同状态之间的有效流转拒绝流转,不同的状态服务处理不同的服务内容。

七、总结

  • 从以上的两种方式对一个需求的实现中可以看到,在第二种使用设计模式处理后已经没有了ifelse,代码的结构也更加清晰易于扩展。这就是设计模式的好处,可以非常强大的改变原有代码的结构,让以后的扩展和维护都变得容易些。
  • 在实现结构的编码方式上可以看到这不再是面向过程的编程,而是面向对象的结构。并且这样的设计模式满足了单一职责开闭原则,当你只有满足这样的结构下才会发现代码的扩展是容易的,也就是增加和修改功能不会影响整体的变化。
  • 但如果状态和各项流转较多像本文的案例中,就会产生较多的实现类。因此可能也会让代码的实现上带来了时间成本,因为如果遇到这样的场景可以按需评估投入回报率。主要点在于看是否经常修改、是否可以做成组件化、抽离业务与非业务功能。

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

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

相关文章

Mysql 中的case-when

什么是 case-when case-when 是一种 sql 语句中的语法结构,结构如下&#xff1a; case 字段名 when 值 then 字段名|值 ... else 字段名|值 end case when 主要用于数据的 行列转换&#xff08;把一列数据转换为多列&#xff09; 前置条件&#xff1a; -- 表…

02.体验CSS以及Bootstrap框架

目录 CSS固定格式 1&#xff09;style标签 2&#xff09;div标签 3&#xff09;span标签 CSS属性 一、文字属性 1.规范文字样式的属性 2.规定文字粗细的属性 3.规定文字大小的属性 4.规范文字字体的属性 二、文本属性 1.文本装饰属性 2.文本水平对齐属性 3.文本缩进…

[flutter]一键将YAPI生成的api.json文件转为需要的Dart Model类的脚本

目的&#xff1a; 根据YAPI接口平台生成的api.json接口文件&#xff0c;将接口数据转化为model类&#xff0c;生成对应的接口值类型文件。 发现&#xff1a; api.json文件导出&#xff1a; YAPi是一个接口管理平台&#xff0c;登录账号打开项目后&#xff0c;在点击数据管理…

Vuex3学习笔记

文章目录 1&#xff0c;入门案例辅助函数 2&#xff0c;mutations传参辅助函数 3&#xff0c;actions辅助函数 4&#xff0c;getters辅助函数 5&#xff0c;模块拆分6&#xff0c;访问子模块的state辅助函数 7&#xff0c;访问子模块的getters辅助函数 8&#xff0c;访问子模块…

Python魔法之旅-魔法方法(23)

目录 一、概述 1、定义 2、作用 二、应用场景 1、构造和析构 2、操作符重载 3、字符串和表示 4、容器管理 5、可调用对象 6、上下文管理 7、属性访问和描述符 8、迭代器和生成器 9、数值类型 10、复制和序列化 11、自定义元类行为 12、自定义类行为 13、类型检…

【Python】数据处理:OS目录文件操作

Python的os模块是一个用于与操作系统进行交互的标准库模块。它提供了丰富的功能来处理文件和目录、执行系统命令、获取和设置环境变量等。 工作目录操作 获取当前工作目录 os.getcwd()参数&#xff1a;无返回值&#xff1a;一个字符串&#xff0c;表示当前工作目录的路径。这…

什么,一不小心打造了一个基于大模型的操作系统

如果以大模型为Kernel, 形成一个新的操作系统&#xff0c;那么&#xff1a; 1. byzer-llm 是这个大模型操作系统的编程接口&#xff0c;有点类似Linux操作系统的C ABI。 2. byzer-retrieval 也被集成进 byzer- llm 接口里&#xff0c;算是大模型操作系统的文件系统&#xff0c…

pytorch 自定义学习率更新 Poly

Poly 学习率调整策略需要继承_LRScheduler类&#xff0c;该类包含三个重要属性和两个重要方法 学习率与batch-size的关系 一般来说&#xff0c;batch-size的大小一般与学习率的大小成正比。batch-size越大一般意味着算法收敛方向的置信度越大&#xff0c;也可以选择较大的学…

STM32快速入门(ADC数模转换)

STM32快速入门&#xff08;ADC数模转换&#xff09; 前言 ADC数模转换存在的意义就是将一些温度传感器、各自数据传感器产生的模拟信号转换成方便识别和计算的数字信号。 导航 图24 通用定时器框图&#xff1a; 图片截取自STM32 F1XX中文参考手册。还是以框图为中心&#x…

FinalShell导出服务器配置信息密码password是加密的,如何解密?

本章教程,主要实现了一个小的功能,对FinalShell导出的配置信息,进行解密。 FinalShell导出之后,会产生一个json文件,例如下面这种json格式,里面记录了服务器的IP地址,端口和密码,里面的密码是经过加密处理的,本文主要利用java代码实现对这个password进行解密还原。 {&…

(论文翻译)Coordinate Attention for Efficient Mobile Network Design(坐标注意力 CVPR2021)

Coordinate Attention for Efficient Mobile Network Design&#xff08;CVPR2021&#xff09; 文章目录 Coordinate Attention for Efficient Mobile Network Design&#xff08;CVPR2021&#xff09;摘要1.引言2.相关工作3.方法&#xff1a;Coordinate Attention3.1.Revisit …

【c++】哈希>unordered容器哈希表哈希桶哈希的应用详解

主页&#xff1a;醋溜马桶圈-CSDN博客 专栏&#xff1a;c_醋溜马桶圈的博客-CSDN博客 gitee&#xff1a;mnxcc (mnxcc) - Gitee.com 目录 1. unordered系列关联式容器 1.1 unordered_map 1.1.1 unordered_map的文档介绍 1.1.2 unordered_map的接口说明 1.1.2.1 unordered_m…

Java学习 - Maven - 常用命令(学习精选)

前言 在上一篇文章中&#xff0c;我们对 Maven 有了初步的了解&#xff0c;包括它的定义、安装步骤以及一些基本的配置方法。Maven 是一个强大的项目管理工具&#xff0c;它可以帮助开发者自动化构建过程&#xff0c;并且管理项目的依赖关系。 今天&#xff0c;我们将深入探讨…

上位机图像处理和嵌入式模块部署(f407 mcu和其他mcu品类的选择)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 很多朋友读书的时候学的是stm32&#xff0c;工作中用的也是stm32。这本来问题不大&#xff0c;但是过去两三年的经历告诉我们&#xff0c;mcu的使用…

【设计模式】行为型设计模式之 职责链模式,探究过滤器、拦截器、Mybatis插件的底层原理

一、介绍 职责链模式在开发场景中经常被用到&#xff0c;例如框架的过滤器、拦截器、还有 Netty 的编解码器等都是典型的职责链模式的应用。 标准定义 GOF 定义&#xff1a;将请求的发送和接收解耦&#xff0c;让多个接收对象都有机会处理这个请求&#xff0c;将这些接收对象…

k8s小型实验模拟

&#xff08;1&#xff09;Kubernetes 区域可采用 Kubeadm 方式进行安装。&#xff08;5分&#xff09; &#xff08;2&#xff09;要求在 Kubernetes 环境中&#xff0c;通过yaml文件的方式&#xff0c;创建2个Nginx Pod分别放置在两个不同的节点上&#xff0c;Pod使用hostPat…

Java | Leetcode Java题解之第139题单词拆分

题目&#xff1a; 题解&#xff1a; public class Solution {public boolean wordBreak(String s, List<String> wordDict) {Set<String> wordDictSet new HashSet(wordDict);boolean[] dp new boolean[s.length() 1];dp[0] true;for (int i 1; i < s.len…

JimuReport 积木报表 v1.7.52 版本发布,免费的低代码报表

项目介绍 一款免费的数据可视化报表工具&#xff0c;含报表和大屏设计&#xff0c;像搭建积木一样在线设计报表&#xff01;功能涵盖&#xff0c;数据报表、打印设计、图表报表、大屏设计等&#xff01; Web 版报表设计器&#xff0c;类似于excel操作风格&#xff0c;通过拖拽完…

智能变电站网络报文记录及故障录波分析装置

是基于Intel X86、PowerPC、FPGA等技术的高度集成化的硬件平台&#xff0c;采用了高性能CPU无风扇散热、网络数据采集、高速数据压缩存储加密等多种技术&#xff0c;实现了高性能计算、多端口同步高速数据采集、数据实时分析、大容量数据存储等功能。 ● 在满足工业标准的同时&…