设计模式 四、行为设计模式(2)
五、状态模式
1、概述
状态设计模式是一种行为型设计模式,它允许对象在其内部状态发生时改变其行为,这种模式可以消除大量的条件语句,并将每个状态的行为封装到单独的类中。
状态模式的主要组成部分如下:
1)上下文(Context):上下文通常包含一个具体状态的引用,用于维护当前状态,上下文委托给当前对象处理状态相关行为。
2)抽象状态(State):定义一个接口,用于封装与上下文的特定状态相关的行为。
3)具体状态(Concrete State):实现抽象状态接口,为具体状态定义行为。每个具体状态类对应一个状态。
简单示例,假设要模拟一个简易的电视遥控器,具有开启、关闭和调整音量的功能。
假设不使用设计模式:
public class TV {private boolean isOn;private int volume;public TV() {isOn = false;volume = 0;}public void turnOn() {// 如果是开启状态if (isOn) {System.out.println("TV is already on.");// 否则打开电视} else {isOn = true;System.out.println("Turning on the TV.");}}public void turnOff() {if (isOn) {isOn = false;System.out.println("Turning off the TV.");} else {System.out.println("TV is already off.");}}public void adjustVolume(int volume) {if (isOn) {this.volume = volume;System.out.println("Adjusting volume to: " + volume);} else {System.out.println("Cannot adjust volume, TV is off.");}}
}
public class Main {public static void main(String[] args) {TV tv = new TV();tv.turnOn();tv.adjustVolume(10);tv.turnOff();}
}
该例子中我们状态比较少,所以代码看起来也不是很复杂,但是状态如果变多了就会变得不好控制,比如增加换台,快捷键,静音等功能。
使用状态设计模式之后:
首先定义抽象状态接口TVState,将每一个修改状态的动作抽象成一个接口:
public interface TVState {void turnOn();void turnOff();void adjustVolume(int volume);
}
接下来为每个具体的状态创建类,实现TVState接口,例如:创建TVOnState 和 TVOffState 类:
// 在on状态下,去执行以下各种操作
public class TVOnState implements TVState {@Overridepublic void turnOn() {System.out.println("TV is already on.");}@Overridepublic void turnOff() {System.out.println("Turning off the TV.");}@Overridepublic void adjustVolume(int volume) {System.out.println("Adjusting volume to: " + volume);}
}
// 在关机的状态下执行以下的操作
public class TVOffState implements TVState {@Overridepublic void turnOn() {System.out.println("Turning on the TV.");}@Overridepublic void turnOff() {System.out.println("TV is already off.");}@Overridepublic void adjustVolume(int volume) {System.out.println("Cannot adjust volume, TV is off.");}
}
接下来定义上下文类TV:
public class TV {// 当前状态private TVState state;public TV() {state = new TVOffState();}public void setState(TVState state) {this.state = state;}public void turnOn() {// 打开state.turnOn();// 设置为开机状态setState(new TVOnState());}public void turnOff() {// 关闭state.turnOff();// 设置为关机状态setState(new TVOffState());}public void adjustVolume(int volume) {state.adjustVolume(volume);}
}
最后通过以下方式使用这些类:
public class Main {public static void main(String[] args) {TV tv = new TV();tv.turnOn();tv.adjustVolume(10);tv.turnOff();}
}
这个例子展示了状态模式的基本结构和用法。通过使用状态模式,我们可以更好地组织和管理与特定状态相关的代码。当状态较多时,这种模式的优势就会凸显出来,同时我们在代码时,因为我们会对每个状态进行独立封装,所以也会简化代码编写。
2、有限状态机
有限状态机,英文翻译时Flinite State Machine,缩写为FSM,简称状态机,比较官方的说法是:有限状态机是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件。状态机有3个组成部分:状态(State)、事件(Event)、动作(Action)。其中,事件也成为转移条件(Transition Condition)。事件触发状态的转移及动作的执行,不过,动作不是必须的,也可能只转移状态,不执行任何动作。
2.1 分支法
如何实现状态机,总结了三种方式。其中,最简单直接的实现方式是,参照状态转移图,将每一个状态转移。原模原样的直译成代码。这样编写的代码会包含大量的 if - else或 switch-case 分支判断逻辑,甚至是嵌套的分支判断逻辑。所以我们把这种方法暂且命名为分支法:
下面是一个使用if-else 语句实现的马里奥形态变化的代码示例:
public class Mario {private MarioState state;public Mario() {state = MarioState.SMALL;}public void handleEvent(Event event) {MarioState newState = state;// 处理吃蘑菇事件if (event == Event.MUSHROOM) {if (state == MarioState.SMALL) {newState = MarioState.BIG;}// 处理吃火花事件} else if (event == Event.FIRE_FLOWER) {if (state == MarioState.BIG) {newState = MarioState.FIRE;}// 处理遇到小怪事件} else if (event == Event.ENEMY_ATTACK) {if (state == MarioState.BIG) {newState = MarioState.SMALL;} else if (state == MarioState.FIRE) {newState = MarioState.BIG;} else if (state == MarioState.SMALL) {newState = MarioState.DEAD;}// 处理掉坑事件} else if (event == Event.FALL_INTO_PIT) {newState = MarioState.DEAD;}System.out.printf("从 %s 变为 %s%n", state, newState);state = newState;}
}
public class MarioDemo {public static void main(String[] args) {Mario mario = new Mario();mario.handleEvent(Event.MUSHROOM); // 变为大马里奥mario.handleEvent(Event.FIRE_FLOWER); // 变为火焰马里奥mario.handleEvent(Event.ENEMY_ATTACK); // 变为死亡马里奥}
}
2.2 查表法
该种方法略,不怎么用,可以自己查资料。
2.3 状态模式
在查表法的代码实现中,事件触发的动作只是简单的状态或者数值,所以,我们用一个 MarioState类型的二维数组 TRANSITION_TABLE 就能表示,二维数组中的值表示出发事件后的新状态。但是,如果要执行的动作并非这么简单,而是一系列复杂的逻辑操作(比如加减分数、处理位置信息等等),我们就没法用如此简单的二维数组来表示了。这也就是说,查表法的实现方式有一定局限性。
虽然分支逻辑的实现方式不存在这个问题,但它又存在前面讲到的其他问题,比如分支判断逻辑较多,导致代码可读性和可维护性不好等。实际上,针对分支逻辑法存在的问题,我们可以使用状态模式来解决。
状态模式通过将事件触发的状态转移和动作执行,拆分到不同的状态类中,来避免分支判断逻辑。我们还是结合代码来理解这句话。利用状态模式,我们来补全 MarioStateMachine 类,补全后的代码如下所示。
以下是一个使用 Java 实现的简化版马里奥形态变化的案例代码,我为代码添加了中文注释以便理解:
// 定义事件枚举类型
enum Event {// 吃蘑菇,吃火花,遇到小怪,调入深坑MUSHROOM, FIRE_FLOWER, ENEMY_ATTACK, FALL_INTO_PIT
}
// 定义马里奥状态接口
interface MarioState {void handleEvent(Event event);
}
// 实现死亡马里奥状态
class DeadMario implements MarioState {private Mario mario;public DeadMario(Mario mario) {this.mario = mario;}@Overridepublic void handleEvent(Event event) {System.out.println("马里奥已死亡,无法处理事件");}
}
// 实现小马里奥状态
class SmallMario implements MarioState {private Mario mario;public SmallMario(Mario mario) {this.mario = mario;}@Overridepublic void handleEvent(Event event) {switch (event) {case MUSHROOM:System.out.println("变为大马里奥");mario.setState(new BigMario(mario));break;case FIRE_FLOWER:System.out.println("小马里奥不能直接变为火焰马里奥");break;case ENEMY_ATTACK:System.out.println("小玛丽奥去世了");mario.setState(new DeadMario(mario));break;case FALL_INTO_PIT:System.out.println("小玛丽奥去世了");mario.setState(new DeadMario(mario));break;}}
}
// 实现大马里奥状态
class BigMario implements MarioState {private Mario mario;public BigMario(Mario mario) {this.mario = mario;}@Overridepublic void handleEvent(Event event) {switch (event) {case MUSHROOM:System.out.println("保持大马里奥");break;case FIRE_FLOWER:System.out.println("变为火焰马里奥");mario.setState(new FireMario(mario));break;case ENEMY_ATTACK:System.out.println("变为小马里奥");mario.setState(new SmallMario(mario));break;case FALL_INTO_PIT:System.out.println("马里奥去世了");mario.setState(new DeadMario(mario));break;}}
}
// 实现火焰马里奥状态
class FireMario implements MarioState {private Mario mario;public FireMario(Mario mario) {this.mario = mario;}@Overridepublic void handleEvent(Event event) {switch (event) {case MUSHROOM:System.out.println("保持火焰马里奥");break;case FIRE_FLOWER:System.out.println("保持火焰马里奥");break;case ENEMY_ATTACK:System.out.println("变为大马里奥");mario.setState(new BigMario(mario));break;case FALL_INTO_PIT:System.out.println("马里奥去世了");mario.setState(new DeadMario(mario));break;}}
}
// 定义马里奥类,作为状态的上下文
class Mario {private MarioState state;public Mario() {state = new SmallMario(this);}public void setState(MarioState state) {this.state = state;}public void handleEvent(Event event) {state.handleEvent(event);}
}
// 测试类
public class MarioDemo {public static void main(String[] args) {Mario mario = new Mario();mario.handleEvent(Event.MUSHROOM); // 变为大马里奥mario.handleEvent(Event.FIRE_FLOWER); // 变为火焰马里奥mario.handleEvent(Event.ENEMY_ATTACK); // 变为大马里奥}
}
在这个简化示例中,我们定义了 MarioState 接口以及实现了 DeadMario 、SmallMario 、 BigMario 和 FireMario 类,分别表示马里奥的四种形态。每个形态类实现了 handleEvent 方法,用于处理不同的游戏事件并根据有限状态机规 则进行状态转换。
Mario 类作为状态的上下文,用于管理和切换马里奥的状态。它有一个 setState方法,用于更新当前状态。 handleEvent 方法将事件传递给当前状态,以便根据事件执行相应的状态转换。
在 MarioDemo 测试类中,我们创建了一个 Mario 实例,并通过调用handleEvent 方法模拟游戏中的事件。通过运行这个测试类,你可以观察到马里奥根据有限状态机的规则在不同形态之间切换。
这个简化示例展示了如何使用有限状态机来实现马里奥角色的形态变化。在实际游戏开发中,你可能需要考虑更多的事件和状态,以及与游戏引擎或框架集成的方式。不过,这个示例可以帮助你理解有限状态机在游戏中的应用。
六、迭代器模式
迭代器模式,它用来遍历集合对象,不过,很多编程语言都将迭代器作为一个基础的类库,直接提供出来了。在平时的开发中,特别是业务开发,我们直接使用即可,很少会自己去实现一个迭代器。不过弄懂原理能帮助我们更好的使用这些工具类。
不怎么用,省略,需要可以自行查询。
七、访问者模式
1、概述和原理
访问者设计模式(Visitor Pattern)是一种行为型设计模式,它允许你再不修改现有类结构的情况下,为类添加新的操作,这种模式可以实现良好的解耦和扩展性,尤其适用于现有类层次结构中添加新的功能的情况。
访问者模式主要包含以下角色:
1. 访问者(Visitor):定义一个访问具体元素的接口,为每种具体元素类型声明一个访问操作。
2. 具体访问者(ConcreteVisitor):实现访问者接口,为每种具体元素提供具体的访问操作实现。
3. 元素(Element):定义一个接口,声明接受访问者的方法。
4. 具体元素(ConcreteElement):实现元素接口,提供接受访问者的具体实现。
5. 对象结构(ObjectStructure):包含一个元素集合,提供一个方法以遍历这些元素并让访问者访问它们。
以下是一个简单的访问者模式示例:
假设我们有一个表示计算机组件的类层次结构(如 CPU、内存和硬盘等),我们需要为这些组件实现一个功能,比如展示它们的详细信息。使用访问者模式,我们可以将【展示详细信息】的功能与【组件类】分离,从而实现解耦和扩展性。
1、不同的元素(被访问的对象)可以接收不同的访问者。
2、不同的访问者会对不同的被访问者产生不同的行为。
3、如果想要扩展,则独立重新实现访问者接口,产生一个新的具体访问者就可以了。
4、他实际解耦的是【被访问者】和【对被访问者的操作】。
简单理解就是不同的访问者,到了同一个被访问对象的家里会干不同的事。这个【事】就是行为,通过访问者模式,我们可以将行为和对象分离解耦,如下图。
// 访问者接口
interface ComputerPartVisitor {// 访问 Computer 对象void visit(Computer computer);// 访问 Mouse 对象void visit(Mouse mouse);// 访问 Keyboard 对象void visit(Keyboard keyboard);
}
// 具体访问者
class ComputerPartDisplayVisitor implements ComputerPartVisitor {// 访问 Computer 对象@Overridepublic void visit(Computer computer) {System.out.println("Displaying Computer.");}// 访问 Mouse 对象@Overridepublic void visit(Mouse mouse) {System.out.println("Displaying Mouse.");}// 访问 Keyboard 对象@Overridepublic void visit(Keyboard keyboard) {System.out.println("Displaying Keyboard.");}
}
// 元素接口
interface ComputerPart {// 接受访问者的访问void accept(ComputerPartVisitor computerPartVisitor);
}
// 具体元素
class Computer implements ComputerPart {// 子元素数组ComputerPart[] parts;public Computer() {// 初始化子元素数组parts = new ComputerPart[]{new Mouse(), new Keyboard()};}// 接受访问者的访问@Overridepublic void accept(ComputerPartVisitor computerPartVisitor) {// 遍历所有子元素并接受访问者的访问for (int i = 0; i < parts.length; i++) {parts[i].accept(computerPartVisitor);}// 访问 Computer 对象本身computerPartVisitor.visit(this);}
}
// 具体元素:鼠标
class Mouse implements ComputerPart {// 接受访问者的访问@Overridepublic void accept(ComputerPartVisitor computerPartVisitor) {// 访问 Mouse 对象computerPartVisitor.visit(this);}
}
// 具体元素:键盘
class Keyboard implements ComputerPart {// 接受访问者的访问@Overridepublic void accept(ComputerPartVisitor computerPartVisitor) {// 访问 Keyboard 对象computerPartVisitor.visit(this);}
}
// 客户端代码
public class VisitorPatternDemo {public static void main(String[] args) {// 创建一个 Computer 对象ComputerPart computer = new Computer();// 创建一个具体访问者ComputerPartVisitor visitor = new ComputerPartDisplayVisitor();// 让 Computer 对象接受访问者的访问computer.accept(visitor);}
}
在这个示例中,我们定义了一个表示计算机组件的类层次结构,包括 Computer 、Mouse 和 Keyboard 。这些类实现了 ComputerPart 接口,该接口声明了一个接受访问者的方法。我们还定义了一个 ComputerPartVisitor 接口,用于访问这些计算机组件,并为每种组件类型声明了一个访问操作。
ComputerPartDisplayVisitor 类实现了 ComputerPartVisitor 接口,为每种计算机组件提供了展示详细信息的功能。在客户端代码中,我们创建了一个Computer 对象和一个 ComputerPartDisplayVisitor 对象。当我们调用computer.accept() 方法时,计算机的所有组件都会被访问者访问,并显示相应的详细信息。
这个示例展示了如何使用访问者模式将功能与类结构分离,实现解耦和扩展性。如果我们需要为计算机组件添加新功能,只需创建一个新的访问者类,而无需修改现有的组件类。这使得在不影响现有代码的情况下,为系统添加新功能变得容易。
// 添加一个更新计算机部件的访问者实现
class ComputerPartUpdateVisitorImpl implements ComputerPartVisitor {// 访问 Computer 对象并执行更新操作@Overridepublic void visit(Computer computer) {System.out.println("Updating Computer.");}// 访问 Mouse 对象并执行更新操作@Overridepublic void visit(Mouse mouse) {System.out.println("Updating Mouse.");}// 访问 Keyboard 对象并执行更新操作@Overridepublic void visit(Keyboard keyboard) {System.out.println("Updating Keyboard.");}
}
// 客户端代码,几乎不用任何修改
public class VisitorPatternDemo {public static void main(String[] args) {// 创建一个 Computer 对象ComputerPart computer = new Computer();// 创建一个具体访问者ComputerPartVisitor visitor = new ComputerPartUpdateVisitorImpl();// 让 Computer 对象接受访问者的访问computer.accept(visitor);}
}
访问者模式可以算是 23 种经典设计模式中最难理解的几个之一。因为它难理解、难实现,应用它会导致代码的可读性、可维护性变差,所以,访问者模式在实际的软件开发中很少被用到,在没有特别必要的情况下,建议你不要使用访问者模式。
2、使用场景
2.1 抽象语法树
访问者模式在实际项目中的一个常见使用场景是处理抽象语法树(AST)。例如,在编译器或解释器中,我们需要处理不同类型的语法结构,如声明、表达式、循环等。 使用访问者模式,我们可以将处理这些结构的功能与结构类分离,实现解耦和扩展性。
以下是一个简单的示例,展示了如何使用访问者模式处理抽象语法树
// AST 节点基类
abstract class AstNode {// 接受访问者的方法abstract void accept(AstVisitor visitor);
}
// 访问者接口
interface AstVisitor {// 访问表达式节点的方法void visit(ExpressionNode node);// 访问数字节点的方法void visit(NumberNode node);// 访问加法节点的方法void visit(AdditionNode node);
// 省略其他节点
}
// 数字节点,表示一个整数值
class NumberNode extends AstNode {int value;// 构造方法,接收一个整数作为值NumberNode(int value) {this.value = value;}// 实现基类的 accept 方法,接受访问者void accept(AstVisitor visitor) {visitor.visit(this);}
}
// 加法节点,表示两个子节点的相加
class AdditionNode extends AstNode {AstNode left;AstNode right;// 构造方法,接收两个子节点AdditionNode(AstNode left, AstNode right) {this.left = left;this.right = right;}// 实现基类的 accept 方法,接受访问者void accept(AstVisitor visitor) {visitor.visit(this);}
}
// 表达式节点,包含一个子节点
class ExpressionNode extends AstNode {AstNode node;// 构造方法,接收一个子节点ExpressionNode(AstNode node) {this.node = node;}// 实现基类的 accept 方法,接受访问者void accept(AstVisitor visitor) {visitor.visit(this);}
}
class AstEvaluator implements AstVisitor {int result;AstEvaluator() {result = 0;}void visit(ExpressionNode node) {node.node.accept(this);}void visit(NumberNode node) {result = node.value;}void visit(AdditionNode node) {node.left.accept(this);int leftValue = result;node.right.accept(this);int rightValue = result;result = leftValue + rightValue;}
}
最后,我们可以使用这个访问者类计算一个简单的 AST
public class Main {public static void main(String[] args) {// 创建一个简单的 AST:(2 + 3)AstNode ast = new ExpressionNode(new AdditionNode(new NumberNode(2),new NumberNode(3)));// 创建一个访问者实例AstEvaluator evaluator = new AstEvaluator();// 使用访问者计算 AST 的结果ast.accept(evaluator);// 输出计算结果System.out.println("AST 的结果是: " + evaluator.result);}
}
相关文章:
设计模式 四、行为设计模式(2)
五、状态模式 1、概述 状态设计模式是一种行为型设计模式,它允许对象在其内部状态发生时改变其行为,这种模式可以消除大量的条件语句,并将每个状态的行为封装到单独的类中。 状态模式的主要组成部分如下: 1)上…...
C++中作用域(public,private,protected
在C中,public、private 和 protected 是用于控制类成员(变量和函数)访问权限的关键字。它们决定了类成员在代码中的可见性和可访问性。在学习时候,对于public是最容易理解的,对于private也好理解,但是对于p…...
Spring配置方式演进:从XML到注解,构建灵活高效的开发体系
Spring配置方式演进:从XML到注解,构建灵活高效的开发体系 在Spring框架的演进长河中,配置方式始终是开发者需要掌握的核心技能。从早期XML一统天下的严谨规范,到注解驱动的敏捷开发,再到如今Java Config的优雅实践&am…...
网络4 OSI7层
OSI七层模型:数据如何传送,向下传送变成了什么样子 应用层 和用户打交道,向用户提供服务。 例如:web服务、http协议、FTP协议 1.用户接口 2.提供各种服务 通过浏览器(接口)提供Web服务 表示层 翻译 我的“…...
前端请求设置credentials: ‘include‘导致的cors问题
1.背景 前端请求设置credentials: ‘include‘其实主要是为了发送凭证,传cookie给后端 2.前端请求 fetch(http://frontend.com, { method: GET, // 或其他HTTP方法 credentials: include, // 不携带凭证 headers: { Content-Type: application/json, }, })…...
LabVIEW中VI Scripting 特定对象解析
该 LabVIEW 程序通过三条并行代码路径,借助 VI Scripting 功能,以特定方式解析程序框图对象,展示了不同方法在处理对象嵌套及特定范围对象时的差异。 上方文字:三条并行代码路径展示了解析程序框图的不同方式。第一条路径使用 …...
CISCO组建RIP V2路由网络
1.实验准备: 2.具体配置: 2.1根据分配好的IP地址配置静态IP: 2.1.1PC配置: PC0: PC1: PC2: 2.1.2路由器配置: R0: Router>en Router#conf t Enter configuration…...
性能飙升50%,react-virtualized-list如何优化大数据集滚动渲染
在处理大规模数据集渲染时,前端性能常常面临巨大的挑战。本文将探讨 react-virtualized-list 库如何通过虚拟化技术和 Intersection Observer API,实现前端渲染性能飙升 50% 的突破!除此之外,我们一同探究下该库还支持哪些新的特性…...
超低功耗MCU软件开发设计中的要点与选型推荐
前沿-超低功耗MCU应用: 超低功耗MCU(微控制器)凭借其极低的功耗和高效的能量管理能力,正在快速渗透到多个新兴领域,尤其在物联网(IoT)、可穿戴设备、智能家居和医疗电子等领域展现出巨大的应用…...
Gson、Fastjson 和 Jackson 对比解析
目录 1. Gson (Google) 基本介绍: 核心功能: 特点: 使用场景: 2. Fastjson (Alibaba) 基本介绍: 核心功能: 特点: 使用场景: 3. Jackson 基本介绍: 核心功能…...
冒泡排序与回调函数——qsort
文章核心内容总结 本文围绕数组排序展开,先介绍了冒泡排序,后引入qsort库函数进行排序,并对二者进行了对比。 1. 冒泡排序实现 在探讨冒泡排序(Bubble Sort)这一经典的排序算法时,我们首先需要了解其基本…...
(四)机器学习---逻辑回归及其Python实现
之前我们提到了常见的任务和算法,本篇我们使用逻辑回归来进行分类 分类问题回归问题聚类问题各种复杂问题决策树√线性回归√K-means√神经网络√逻辑回归√岭回归密度聚类深度学习√集成学习√Lasso回归谱聚类条件随机场贝叶斯层次聚类隐马尔可夫模型支持向量机高…...
微信小程序开发:微信小程序上线发布与后续维护
微信小程序上线发布与后续维护研究 摘要 微信小程序作为移动互联网的重要组成部分,其上线发布与后续维护是确保其稳定运行和持续优化的关键环节。本文从研究学者的角度出发,详细探讨了微信小程序的上线发布流程、后续维护策略以及数据分析与用户反馈处理的方法。通过结合实…...
vue拓扑图组件
vue拓扑图组件 介绍技术栈功能特性快速开始安装依赖开发调试构建部署 使用示例演示截图组件源码 介绍 一个基于 Vue3 的拓扑图组件,具有以下特点: 1.基于 vue-flow 实现,提供流畅的拓扑图展示体验 2.支持传入 JSON 对象自动生成拓扑结构 3.自…...
Python数据分析-NumPy模块-查看数组属性
查看数组的行数和列数 from numpy import array aarray([[1,1],[2,2],[3,3]]) print(a.shape)结果: 提取数组的行数或列数 from numpy import array aarray([[1,1],[2,2],[3,3]]) print(a.shape) print(a.shape[0]) print(a.shape[1])结果: 查看数组…...
ch07课堂参考代码
DFS 的优化 1) 标记搜索过的状态 用数组标记一个状态是否被搜索过,搜索过则直接 return,不用再执行函数,用于保证每个状态只被搜索一次。 在递归调用函数之前,通过 if (vis[x]) 判断 x 是否被搜索过,搜索过则直接ret…...
去重新闻数据中重复的正文内容(body 字段),并把唯一的新闻内容保存到一个新的 JSON 文件中
示例代码: import os import json import nltk from tqdm import tqdmdef wr_dict(filename,dic):if not os.path.isfile(filename):data []data.append(dic)with open(filename, w) as f:json.dump(data, f)else: with open(filename, r) as f:data json.l…...
centos crontab 设置定时任务访问链接
在 CentOS 系统中,使用 crontab 设置定时任务访问 URL,可以通过命令行工具(如 curl 或 wget)发送 HTTP 请求。以下是详细步骤: 1、安装必要工具(若未安装) 安装 curl 或 wget # 安装 curl su…...
oracle大师认证证书有用吗
专业能力的高度认可:OCM 是 Oracle认证的最高级别,是对数据库从业人员技术、知识和操作技能的最高级认可,也是 IT 界顶级认证之一。它表明持证者具备处理关键业务数据库系统和应用的能力,能够解决最困难的技术难题和最复杂的系统故…...
说说对 Node 中的 process 的理解?有哪些常用方法?
1. 简介 process对象是Node.js中的全局变量,它提供了有关当前Node.js进程的信息并允许对其进行控制。通过process对象,我们可以获取进程的环境变量、命令行参数,控制进程的行为以及与其他进程进行通信。 2. 常用属性 process.env process…...
maven 和 idea intej步骤记录
1 maven 安装配置 1.1 参考链接安装 maven参考链接 1.2 maven 关联本机jdk版本 配置 priofiles jdk 版本时,查看本本机jdk 版本:环境变量查看jdk 路径版本: java_home 变量路径是C:\Program Files\Java\jdk-21 # setting.xml <profile&…...
Java Socket编程从零到实战详解
摩西摩西~最近接单子用到了Java的socket编程,顺手给整理下来咯! 各个语言的socket编程除了语法之外几乎思路都是一样的。 所以这些思路都是可以直接移植到其他语言实现的! 话不多说上车! 一、Socket基础概念与工作流程…...
STM32中Hz和时间的转换
目录 一、常见的频率单位及其转换 二、计算公式 三、STM32中定时器的应用 四、例子 一、常见的频率单位及其转换 赫兹(Hz)是频率的国际单位,表示每秒钟周期性事件发生的次数。 1 kHz(千赫兹) 1,000 Hz1 MHz&#…...
Apache Hive学习教程
什么是Hive? Apache Hive是一款建立在Hadoop之上的开源数据仓库系统,可以将存储在Hadoop文件中的结构化、半结构化 数据文件映射为一张数据库表,基于表提供了一种类似SQL的查询模型,称为Hive查询语言(HQL)&…...
学习笔记六——Rust 切片全解析
这篇文章不是告诉你“切片是啥”,而是让你真正理解并学会用切片,同时还会把你最容易卡壳的 {:?}、char_indices() 等都讲清楚! 📚 文章目录 切片到底是什么?能不能通俗一点?切片的本质:它其实…...
Apache Doris SelectDB 技术能力全面解析
Apache Doris 是一款开源的 MPP 数据库,以其优异的分析性能著称,被各行各业广泛应用在实时数据分析、湖仓融合分析、日志与可观测性分析、湖仓构建等场景。Apache Doris 目前被 5000 多家中大型的企业深度应用在生产系统中,包含互联网、金融、…...
设计模式 Day 8:策略模式(Strategy Pattern)完整讲解与实战应用
🔄 前情回顾:Day 7 重点回顾 在 Day 7 中,我们彻底讲透了观察者模式: 它是典型的行为型模式,核心理念是“一变多知”,当一个对象状态变化时,自动通知所有订阅者。 我们通过 RxCpp 实现了工业…...
HarmonyOS-ArkUI V2装饰器-@Once
前文,关于Param的使用: HarmonyOS-ArkUIV2装饰器-Param:组件外部输入-CSDN博客 Once装饰器是一个需要配合Param装饰器一块使用的的装饰器。它的特性是,仅仅在变量进行初始化的时候,接受一个外部传来的值进行初始化&am…...
前端Node.js的包管理工具npm指令
npm(Node Package Manager)是Node.js的包管理工具,主要用于安装、更新、删除和管理JavaScript包。以下是前端开发中常用的npm命令及其用途: 基本命令 npm提供了一系列命令行工具,用于执行各种包管理操作。以下是一…...
本地搭建直播录屏应用并实现使用浏览器远程控制直播间录屏详细教程
 本文主要介绍如何在 Windows 系统电脑本地部署直播录屏工具 Bililive-go,并结合 cpolar 内网穿透工具实现远程访问本地 Bililive-go 服务 web 界面管理录屏任务。 相信很多小伙伴都喜欢看直播,不过如果一旦临时有事看不了直播,…...
Hydra Columnar:一个开源的PostgreSQL列式存储引擎
Hydra Columnar 是一个 PostgreSQL 列式存储插件,专为分析型(OLAP)工作负载设计,旨在提升大规模分析查询和批量更新的效率。 Hydra Columnar 以扩展插件的方式提供,主要特点包括: 采用列式存储,…...
OpenGL学习笔记(assimp封装、深度测试、模板测试)
目录 模型加载Assimp网格模型及导入 深度测试深度值精度深度缓冲的可视化深度冲突 模板测试物体轮廓 GitHub主页:https://github.com/sdpyy1 OpenGL学习仓库:https://github.com/sdpyy1/CppLearn/tree/main/OpenGLtree/main/OpenGL):https://github.com/sdpyy1/CppL…...
自动化备份全网服务器数据平台
1.项目说明 1.1概述 该项目共分为2个子项目,由环境搭建和实施备份两部分组成 该项目旨在复习巩固系统服务部署使用、shell编程等知识,旨在让学生增加知识面,提高项目实习经历,充实简历 1.2项目组织方式及时间 时间:…...
Trea CN多多与主流AI编程工具万字解析
Trea CN多多与主流AI编程工具万字解析 (含数学建模、架构图、开发流程可视化) 一、数学建模:代码生成效率量化模型 1.1 全链路效率公式 T total N ⋅ ( 1 λ C S ) T check (1) T_{\text{total}} N \cdot \left( \frac{1}{\lambda} \…...
Django从零搭建卖家中心注册页面实战
在电商系统开发中,卖家中心是一个重要的组成部分,而用户注册与登陆则是卖家中心的第一步。本文将详细介绍如何使用Django框架从零开始搭建一个功能完善的卖家注册页面,包括前端界面设计和后端逻辑实现。 一、项目概述 我们将创建一个名为sel…...
如何进行预算考核
✅ 一、预算考核体系总体架构 模块内容说明考核内容1. 预算目标/指标完成情况2. 预算编制/执行情况双轮驱动,目标 + 执行双考核考核对象高层、中层、基层、后台支持分层分类考核考核周期月度(滚动)+ 季度(校验)+ 年度(决算)提高适应性和准确性考核工具指标体系、差错率评…...
django相关面试题
django相关面试题 1.django的生命周期 2.django中的orm查询如何自定义方法 3.django中的中间件的作用 4.django中间件,request进来经过哪些中间件,顺序是怎么样的 5.django中的csrf是什么 6.django每访问一次数据库都会创建一个连接吗 7.uwsgi gunicorn…...
【Java面试系列】Spring Cloud微服务架构中的分布式事务实现与性能优化详解 - 3-5年Java开发必备知识
【Java面试系列】Spring Cloud微服务架构中的分布式事务实现与性能优化详解 - 3-5年Java开发必备知识 引言 在微服务架构中,分布式事务是一个不可避免的挑战。随着业务复杂度的提升,如何保证跨服务的数据一致性成为面试中的高频问题。本文将从基础到进…...
PostgreSQL 17深度解析(从17.0-17.4)
PostgreSQL 17自2024年9月发布以来,持续通过小版本迭代增强功能、优化性能并修复安全漏洞。本文将从17.0到17.4的每个版本切入,深度解析其新增特性、技术原理、性能提升及实践价值,帮助开发者、DBA及架构师全面掌握PostgreSQL 17的演进脉络。 一、PostgreSQL 17.0:基石奠定…...
人物4_Japanese
Now, I start my JaPan【Tokyo】 life, 【I go out of my country{China}, the reason is I want learn more new computer technologies in foreign, also it could let me know more different culture.】I like the place and most persons in here. The JaPan culture have…...
Go 语言中的 package main、 func main() 和main.go的使用规范
本文旨在解释 Go 语言中 package main 、 func main() 和main.go的关系及其使用规则,解决如下典型问题: 是否可以在一个项目中定义多个 func main()?是否可以在非 package main 中写 func main()?多个文件中都写 func main() 会冲…...
mac 终端 code 命令打开 vscode,修改 cursor占用
rm /usr/local/bin/code vim ~/.zshrc # 定义 cursor 函数,用于打开 Cursor 应用 function cursor {open -a "/Applications/Cursor.app" "$" }# 定义 code 函数,用于打开 Visual Studio Code function code {open -a "/Appli…...
【常用功能】下载文件和复制到剪切板
前言 前端人员在开发时经常会遇到: 后端给一个地址,需要去下载的需求。将页面的内容复制到剪切板 下载文件 我们先说下载文件,通常情况下我们会自己写上一个非常简单的工具函数。 思路如下: 创建一个a元素设置a元素跳转的链接…...
【ESP32-microros(vscode-Platformio)】
一、步骤 1、目前支持ESP32 2、同一个局域网 3、上位机要安装代理(电脑或者linux设备) 4、可直接通过USB下载,也可以使用官方烧录工具,具体的分区表地址要从USB烧录的时候日志查看,一共四个文件,第三个…...
如何使用AI辅助开发CSS3 - 通义灵码功能全解析
一、引言 CSS3 作为最新的 CSS 标准,引入了众多新特性,如弹性布局、网格布局等,极大地丰富了网页样式的设计能力。然而,CSS3 的样式规则繁多,记忆所有规则对于开发者来说几乎是不可能的任务。在实际开发中,…...
OpenCV图像形态学详解
文章目录 一、什么是图像形态学?二、基本概念:结构元素三、基本形态学操作1. 腐蚀(Erosion)2. 膨胀(Dilation)3. 开运算(Opening)4. 闭运算(Closing) 四、高级…...
Java-servlet(完结篇)过滤器乱码解决与监听器
Java-servlet(完结篇)过滤器乱码解决与监听器 前言一、过滤器乱码解决二、监听器1. HttpSessionListener2. ServletContextListener3. ServletRequestListener 三、监听器的使用场景Java-servlet 结语 前言 在之前的 Java Servlet 学习中,我…...
【发布】dtns协议的js-sdk(实现a2a协议:agent2agent)
【发布】dtns协议的js-sdk(实现a2a协议:agent2agent) dtns协议简介 dtns协议是用于dtns.network分布式智体网络的通讯协议。主要目标是将各个独立的智体节点,通过dtns协议(dtns.network)连接在一起&#…...
深度学习总结(8)
模型工作流程 模型由许多层链接在一起组成,并将输入数据映射为预测值。随后,损失函数将这些预测值与目标值进行比较,得到一个损失值,用于衡量模型预测值与预期结果之间的匹配程度。优化器将利用这个损失值来更新模型权重。 下面是…...
[特殊字符] Hyperlane:为现代Web服务打造的高性能Rust文件上传解决方案
🚀 Hyperlane:为现代Web服务打造的高性能Rust文件上传解决方案 ▎开发者必备:为什么选择Hyperlane处理大文件上传? 在实时数据爆炸式增长的时代,开发者面临两大核心挑战: 如何实现TB级大文件的可靠传输如…...