设计模式之迭代器模式与命令模式详解和应用
目录
- 1 迭代器模式
- 1.1 目标
- 1.2 内容定位
- 1.3 迭代器模式
- 1.4 迭代器模式的应用场景
- 1.5 手写字定义的送代器
- 1.6 迭代器模式在源码中的体现
- 1.7 迭代器模式的优缺点
- 2 命令模式
- 2.1 定义
- 2.2 命令模式的应用场景
- 2.3 命令模式在业务场景中的应用
- 2.4 命令模式在源码中的体现
- 2.5 命令模式的优缺点
1 迭代器模式
1.1 目标
1、 了解迭代器模式和命令的应用场景。
2、 自己手写迭代器
3、 掌握迭代器模式和命令模式在源码中的应用,知其所以然。
1.2 内容定位
听说过迭代器模式和命令模式,但并不知其所以然的人群。
1.3 迭代器模式
迭代器模式( Iterator Pattern ) 又称为游标模式(Cursor Pattern), 它提供一种顺序访问集合/ 容器对象元素的方法,而又无须暴露集合内部表示。迭代器模式可以为不同的容器提供一致的 遍历行为,而不用关心容器内容元素组成结构,属于行为型模式。
原文 : Provide a way to access the elements of an aggregate object sequentially without exposing its under lying representation.
解释:提供一种顺序访问集合/容器对象元素的方法,而又无须暴露集合内部表示。
迭代器模式的本质是抽离集合对象迭代行为到迭代器中,提供一致访问接口。
1.4 迭代器模式的应用场景
迭代器模式在我们生活中应用的得也比较广泛,比如物流系统中的传送带,不管传送的是什 么物品,都被打包成一个一个的箱子并且有一个统一的二维码。这样我们不需要关心箱子里面 是啥,我们在分发时只需要一个一个检查发送的目的地即可。再比如,我们平时乘坐交通工具, 都是统一刷卡或者刷脸进站,而不需要关心是男性还是女性、是残疾人还是正常人等个性化的信息。
我们把多个对象聚在一起形成的总体称之为集合(Aggregate), 集合对象是能够包容一组对 象的容器对象。不同的集合其内部元素的聚合结构可能不同,而迭代器模式屏蔽了内部元素获 取细节,为外部提供一致的元素访问行为,解耦了元素迭代与集合对象间的耦合,并且通过提 供不同的迭代器,可以为同个集合对象提供不同顺序的元素访问行为,扩展了集合对象元素迭 代功能,符合开闭原则。迭代器模式适用于以下场景:
1、 访问一个集合对象的内容而无需暴露它的内部表示;
2、 为遍历不同的集合结构提供一个统一的访问接口。
首先来看下迭代器模式的通用UML类图:
从 UML类图中,我们可以看到,迭代器模式主要包含三种角色:
抽象迭代器( Iterator) : 抽象迭代器负责定义访问和遍历元素的接口 ;
具体迭代器( Concreteiterator) :提供具体的元素遍历行为;
抽象容器(Aggregate ) : 负责定义提供具体迭代器的接口 ;
具体容器(ConcreteAggregate ) :创建具体迭代器。
1.5 手写字定义的送代器
总体来说,迭代器模式还是非常简单的。我们还是以课程为例,下面我们自己创建一个课程的集合,集合中的每一个元素就是课程对象,然后自己手写一个迭代器,将每一个课程对象的信息读出来。
首先创建集合元素课程Course类 :
public class Course {private String name;public Course(String name) {this.name = name;}public String getName() {return name;}}
然后创建自定义迭代器Iterator接口 :
public interface Iterator<E> {E next();boolean hasNext();}
然后创建自定义的课程的集合ICourseAggregate接口 :
public interface ICourseAggregate {void add(Course course);void remove(Course course);Iterator<Course> iterator();}
然后,分别实现迭代器接口和集合接口,创建Iteratorlmpl实现类:
public class IteratorImpl<E> implements Iterator<E> {private List<E> list;private int cursor;private E element;public IteratorImpl(List<E> list) {this.list = list;}public E next() {System.out.print("当前位置 " + cursor + " : ");element = list.get(cursor);cursor ++;return element;}public boolean hasNext() {if(cursor > list.size() - 1){return false;}return true;}}
创建课程集合CourseAggregatelmpI 实现类:
public class CourseAggregateImpl implements ICourseAggregate {private List courseList;public CourseAggregateImpl() {this.courseList = new ArrayList();}public void add(Course course) {courseList.add(course);}public void remove(Course course) {courseList.remove(course);}public Iterator<Course> iterator() {return new IteratorImpl<Course>(courseList);}}
然后,编写客户端代码:
public class Test {public static void main(String[] args) {Course java = new Course("Java架构");Course javaBase = new Course("Java基础");Course design = new Course("设计模式");Course ai = new Course("人工智能");ICourseAggregate aggregate = new CourseAggregateImpl();aggregate.add(java);aggregate.add(javaBase);aggregate.add(design);aggregate.add(ai);System.out.println("===========课程列表==========");printCourse(aggregate);aggregate.remove(ai);System.out.println("===========删除操作之后的课程列表==========");printCourse(aggregate);}private static void printCourse(ICourseAggregate aggregate) {Iterator<Course> i = aggregate.iterator();while (i.hasNext()){Course course = i.next();System.out.println("《" + course.getName() + "》");}}}
运行结果如下:
看到这里,小伙伴们肯定会有一种似曾相识的感觉,让人不禁想起我们每天都在用的JDK 自带的结合迭代器。下面我们就来看看源码中是如何运用迭代器的。
1.6 迭代器模式在源码中的体现
先来看JDK中大家非常熟悉的Iterator源码 :
public interface Iterator<E> {boolean hasNext();E next();default void remove() {throw new UnsupportedOperationException("remove");}default void forEachRemaining(Consumer<? super E> action) {Objects.requireNonNull(action);while (hasNext())action.accept(next());}}
从上面代码中,我们看到两个主要的方法定义hasNext()和 next()方 法 ,和我们自己写的完 全一致。
另外,从上面的代码中,我们看到removeO方法实现似曾相识。其实是在组合模式中我们 见到过。迭代器模式和组合模式,两者似乎存在一定的相似性。组合模式解决的是统一树形结 构各层次访问接口,迭代器模式解决的是统一各集合对象元素遍历接口。虽然他们的适配场景 不同,但核心理念是相通的。
下面接看来看Iterator的实现类,其实在我们常用的ArrayList中有一个内部实现类Itr ,它 就实现了 Iterator接口 :
public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable{private class Itr implements Iterator<E> {int cursor; // index of next element to returnint lastRet = -1; // index of last element returned; -1 if no suchint expectedModCount = modCount;public boolean hasNext() {return cursor != size;}@SuppressWarnings("unchecked")public E next() {checkForComodification();int i = cursor;if (i >= size)throw new NoSuchElementException();Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length)throw new ConcurrentModificationException();cursor = i + 1;return (E) elementData[lastRet = i];}...}}
其中hasNextO方法和next()方法实现也非常简单,我们继续往下看在ArrayList内部还有 几个迭代器对Itr进行了进一步扩展,首先看Listltr :
private class ListItr extends Itr implements ListIterator<E> {ListItr(int index) {super();cursor = index;}public boolean hasPrevious() {return cursor != 0;}public int nextIndex() {return cursor;}public int previousIndex() {return cursor - 1;}...
}
它增加了 hasPreviousQ方法是否还有上一个等这样的判断。另外还有SubList对子集合的迭代处理。
当然,迭代器模式在MyBatis中也是必不可少的,来看一个Defaultcursor类 :
public class DefaultCursor<T> implements Cursor<T> {...private final CursorIterator cursorIterator = new CursorIterator();
}
首先它实现了 Cursor接 口 ,而且定义了一个成员变量cursoriterator , 我继续查看 Cursoriterator的源代码发现, 它 是 Defaultcursor的一个内部类,并且实现了 JDK中的 Iterater 接口。
1.7 迭代器模式的优缺点
优点:
1、 多态迭代:为不同的聚合结构提供一致的遍历接口,即一个迭代接口可以访问不同的集合对 象 ;
2、 简化集合对象接口 :迭代器模式将集合对象本身应该提供的元素迭代接口抽取到了迭代器中 ,使集合对象无须关心具体迭代行为;
3、 元素迭代功能多样化:每个集合对象都可以提供一个或多个不同的迭代器,使的同种元素聚合结构可以有不同的迭代行为;
4、解耦迭代与集合:迭代器模式 封装了具体的迭代算法,迭代算法的变化,不会影响到集合对象的架构。
缺点:
1、对于比较简单的遍历(像数组或者有序列表) ,使用迭代器方式遍历较为繁琐。 在日常开发当中,我们几乎不会自己写迭代器。除非我们需要定制一个自己实现的数据结构 对应的迭代器,否则,开源框架提供给我们的API完全够用。
2 命令模式
2.1 定义
命令模式(Command Pattern )是对命令的封装,每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行操作。命令模式解耦了请求方和接收方,请求方只需请求执行命令,不用关心命令是怎样被接收,怎样被操作以及是否被执行…等。 命令模式属于行为型模式。
原 文 : Encapsulate a request as an object, there by letting you parameterize clients with different requests, queue or log requests,and support undoable operations.
解释:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。
在软件系统中,行为请求者与行为实现者通常是一种紧耦合关系,因为这样的实现简单明了。 但紧耦合关系缺乏扩展性,在某些场合中,当需要为行为进行记录,撤销或重做等处理时,只 能修改源码。而命令模式通过为请求与实现间引入一个抽象命令接口,解耦了请求与实现,并 且中间件是抽象的,它可以有不同的子类实现,因此其具备扩展性。所以,命令模式的本质是 解耦命令请求与处理。
2.2 命令模式的应用场景
当系统的某项操作具备命令语义时,且命令实现不稳定(变化),那么可以通过命令模式解耦请求与实现,利用抽象命令接口使请求方代码架构稳定,封装接收方具体命令实现细节。接收方与抽象命令接口呈现弱耦合(内部方法无需一致),具备良好的扩展性。
命令模式适用于 以下应用场景:
1、现实语义中具备"命令"的操作(如命令菜单,shell命令…);
2、请求调用者和请求的接收者需要解耦,使得调用者和接收者不直接交互;
3、需要抽象出等待执行的行为,比如撤销(Undo)操作和恢复(Redo)等操作;
4、需要支持命令宏(即命令组合操作)。
首先看下命令模式的通用UML类图:
从 UML类图中,我们可以看到,命令模式 主要包含四种角色:
接收者角色(Receiver):该类负责具体实施或执行一个请求;
命令角色(Command ):定义需要执行的所有命令行为;
具体命令角色(Concrete Command )该类内部维护一个接收者(Receiver ),在其execute() 方法中调用Receiver的相关方法;
请求者角色(Invoker):接收客户端的命令,并执行命令。
从命令模式的UML类图中,其实可以很清晰地看出:Command的出现就是作为Receiver 和 Invoker的中间件,解耦了彼此。而之所以引入Command中间件,我觉得是以下两方面原因 :
解耦请求与实现:即解耦了 Invoker和 Receiver , 因为在UML类图中,Invoker是一个具 体的实现,等待接收客户端传入命令(即 Invoker与客户端耦合),Invoker处于业务逻辑区域, 应当是一个稳定的结构。而 Receiver是属于业务功能模块 是经常变动的 如果没有Command z 则 Invoker紧耦合Receiver , 一个稳定的结构依赖了一个不稳定的结构,就会导致整个结构都不稳定了。这也就是Command引入的原因:不仅仅是解耦请求与实现,同时稳定( Invoker) 依赖稳 定 (Command ),结构还是稳定的。
扩展性增强:扩展性体现在两个方面:
1、 Receiver属于底层细节,可以通过更换不同的Receiver达到不同的细节实现;
2、 Command接口本身就是抽象的,本身就具备扩展性;而且由于命令对象本身就具备抽 象 ,如果结合装饰器模式,功能扩展简直如鱼得水。
注:在一个系统中,不同的命令对应不同的请求,也就是说无法把请求抽象化,因此命令模式中的Receiver是具体实 现;但是如果在某一个模块中,可以对Receiver进行抽象,其实这就变相使用到了桥接模式(Command类具备两个变 化的维度:Command和 Receiver), 这样子的扩展性会更加优秀。
举个生活中的例子,相信80后的小伙伴应该都经历过普及黑白电视机的那个年代。黑白电 视机要换台那简直不容易,需要人跑上前去用力掰动电视机上那个切换频道的旋钮,一 顿 〃啪 啪啪〃折腾下来才能完成一次换台。如今时代好了,我们只需躺沙发上按一下遥控器就完成了 换台。这就是用到了命令模式,将换台命令和换台处理进行了分离。
另外,就是餐厅的点菜单,一般是后厨先把所有的原材料组合配置好了,客户用餐前只需要 点菜即可,将需求和处理进行了解耦。
2.3 命令模式在业务场景中的应用
假如我们自己开发一个播放器,播放器有播放功能、有拖动进度条功能、停止播放功能、暂 停功能,我们自己去操作播放器的时候并不是直接调用播放器的方法,而是通过一个控制条去传达指令给播放器内核,那么具体传达什么指令,会被封装为一个一个的按钮。那么每个按钮 的就相当于是对一条命令的封装。用控制条实现了用户发送指令与播放器内核接收指令的解耦。
下面来看代码,首先创建播放器内核GPlayer类:
public class GPlayer {public void play(){System.out.println("正常播放");}public void speed(){System.out.println("拖动进度条");}public void stop(){System.out.println("停止播放");}public void pause(){System.out.println("暂停播放");}
}
创建命令接口 IAction类:
public interface IAction {void execute();
}
然后分别创建操作播放器可以接受的指令,播放指令PlayAction类 :
public class PlayAction implements IAction {private GPlayer gplayer;public PlayAction(GPlayer gplayer) {this.gplayer = gplayer;}public void execute() {gplayer.play();}
}
暂停指令PauseAction类 :
public class PauseAction implements IAction {private GPlayer gplayer;public PauseAction(GPlayer gplayer) {this.gplayer = gplayer;}public void execute() {gplayer.pause();}
}
拖动进度条指令SpeedAction类 :
public class SpeedAction implements IAction {private GPlayer gplayer;public SpeedAction(GPlayer gplayer) {this.gplayer = gplayer;}public void execute() {gplayer.speed();}
}
停止播放指令StopAction类 :
public class StopAction implements IAction {private GPlayer gplayer;public StopAction(GPlayer gplayer) {this.gplayer = gplayer;}public void execute() {gplayer.stop();}
}
最后 ,创建控制条Controller类 :
public class Controller {private List<IAction> actions = new ArrayList<IAction>();public void addAction(IAction action){actions.add(action);}public void execute(IAction action){action.execute();}public void executes(){for (IAction action:actions) {action.execute();}actions.clear();}
}
从上面代码来看,控制条可以执行单条命令,也可以批量执行多条命令。下面来看客户端测试代码:
public class Test {public static void main(String[] args) {GPlayer player = new GPlayer();Controller controller = new Controller();controller.execute(new PlayAction(player));controller.addAction(new PauseAction(player));controller.addAction(new PlayAction(player));controller.addAction(new StopAction(player));controller.addAction(new SpeedAction(player));controller.executes();}
}
运行效果如下:
正常播放
暂停播放
正常播放
停止播放
拖动进度条
由于控制条已经与播放器内核解耦了,以后如果想扩展新命令,只需增加命令即可,控制条 的结构无需改动。
2.4 命令模式在源码中的体现
首先来看JDK中的Runnable接口 ,实际上Runnable就相当于是命令的抽象,只要是实现 了 Runnable接口的类都被认为是一个线程。
public interface Runnable { public abstract void run();
}
实际上调用线程的start()方法之后,就有资格去抢CPU资源,而不需要我们自己编写获得 CPU资源的逻辑。而线程抢到CPU资源后,就会执行run()方法中的内容,用 Runnable接口 把用户请求和CPU执行进行了解耦。
然 后 ,再看一个大家非常孰悉的junit.framework.Test接口 :
package junit.framework;
public interface Test { public abstract int countTestCases(); public abstract void run(TestResult result);
}
Test接口中有两个方法,第一个是countTestCases()方法用来统计当前需要执行的测试用例 总数。第二个是run()方法就是用来执行具体的测试逻辑,其参数TestResult是用来返回测试结果的。 实际上我们在平时编写测试用例的时候,只需要实现Test接口即便认为就是一个测试用例,那 么在执行的时候就会自动识别。实际上我们平时通常做法都是继承TestCase类 ,我们不妨来看 —下 TestCase的源码:
public abstract class TestCase extends Assert implements Test { ...public void run(TestResult result) { result.run(this);}...
}
实际上TestCase类它也实现了 Test接口。我们继承TestCase类 ,相当于也实现了 Test 接口,自然也就会被扫描成为一个测试用例。
2.5 命令模式的优缺点
优点:
1、通过引入中间件(抽象接口),解耦了命令请求与实现;
2、 扩展性良好,可以很容易地增加新命令;
3、 支持组合命令,支持命令队列;
4、可以在现有命令的基础上,增加额外功能(比如日志记录…,结合装饰器模式更酸爽)。
缺点:
1、 具体命令类可能过多;
2、 命令模式的结果其实就是接收方的执行结果,但是为了以命令的形式进行架构,解耦请求与 实现,引入了额外类型结构(引入了请求方与抽象命令接口),增加了理解上的困难(不过这 也是设计模式带来的一个通病,抽象必然会引入额外类型;抽象肯定比紧密难理解)。
相关文章:

设计模式之迭代器模式与命令模式详解和应用
目录1 迭代器模式1.1 目标1.2 内容定位1.3 迭代器模式1.4 迭代器模式的应用场景1.5 手写字定义的送代器1.6 迭代器模式在源码中的体现1.7 迭代器模式的优缺点2 命令模式2.1 定义2.2 命令模式的应用场景2.3 命令模式在业务场景中的应用2.4 命令模式在源码中的体现2.5 命令模式的…...

【QA】[Vue/复选框全选] v-model绑定每一项的赋初值问题
发生场景:不只是复选框的状态改变,还有的功能要用到复选框的选中状态,比如:购物车计算总价,合计等等。 引入:复选框 checkbox 在使用时,需要用v-model绑定布尔值,来获取选中状态&…...

python基于django+vue微信小程序的校园二手闲置物品交易
在大学校园里,存在着很多的二手商品,但是由于信息资源的不流通以及传统二手商品信息交流方式的笨拙,导致了很多仍然具有一定价值或者具有非常价值的二手商品的囤积,乃至被当作废弃物处理。现在通过微信小程序的校园二手交易平台,可以方便快捷的发布和交流任何二手商品的信息,并…...

设计模式之观察者模式
什么是观察者模式 观察者模式定义了对象之间一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象都能收到通知并自动刷新。 观察者模式主要包含以下几个角色: Subject(目标):指被观察的对…...

Java Lambda表达式
目录1 Lambda表达式1.1 函数式编程思想概括1.2 Lambda表达式标准格式1.3 Lambda表达式练习1(抽象方法无参无返回值)1.4 Lambda表达式练习2(抽象方法带参无返回值)1.5 Lambda表达式练习2(抽象方法带参带返回值ÿ…...

【1237. 找出给定方程的正整数解】
来源:力扣(LeetCode) 描述: 给你一个函数 f(x, y) 和一个目标结果 z,函数公式未知,请你计算方程 f(x,y) z 所有可能的正整数 数对 x 和 y。满足条件的结果数对可以按任意顺序返回。 尽管函数的具体式子…...

java基础学习 day41(继承中成员变量和成员方法的访问特点,方法的重写)
继承中,成员变量的访问特点 a. name前什么都不加,name变量的访问采用就近原则,先在局部变量中查找,若没找到,继续在本类的成员变量中查找,若没找到,继续在直接父类的成员变量中查找,…...

【c语言进阶】深度剖析整形数据
🚀write in front🚀 📜所属专栏: 🛰️博客主页:睿睿的博客主页 🛰️代码仓库:🎉VS2022_C语言仓库 🎡您的点赞、关注、收藏、评论,是对我最大的激励…...

【信息系统项目管理师】项目管理十大知识领域记忆敲出(采购风险沟通干系人)
【信息系统项目管理师】项目管理十大知识领域记忆敲出(采购风险沟通干系人) 这里写目录标题【信息系统项目管理师】项目管理十大知识领域记忆敲出(采购风险沟通干系人)一.项目采购管理记忆敲出1.合同管理:2.规划采购管…...

[LeetCode 1237]找出给定方程的正整数解
题目描述 题目链接:[LeetCode 1237]找出给定方程的正整数解 给你一个函数 f(x, y) 和一个目标结果 z,函数公式未知,请你计算方程 f(x,y) z 所有可能的正整数 数对 x 和 y。满足条件的结果数对可以按任意顺序返回。 尽管函数的具体式子未知…...

6.2 构建 RESTful 应用接口
第6章 构建 RESTful 服务 6.1 RESTful 简介 6.2 构建 RESTful 应用接口 6.3 使用 Swagger 生成 Web API 文档 6.4 实战:实现 Web API 版本控制 6.2 构建 RESTful 应用接口 6.2.1 Spring Boot 对 RESTful 的支持 Spring Boot 提供的spring-boot-starter-web组件完全…...

20230218英语学习
How Italian Artist’s Mild Colors Dominate World of Design 温柔的“莫兰迪色”,如何引领设计时尚? The Morandi color scheme has become an across-the-board fashion that now prevails in the world of design.Soft and sophisticated Morandi c…...

Linux单一服务管理systemctl
基本上systemd这个启动服务机制只有systemctl命令来处理,所以全部的操作都需要使用systemctl systemctl管理单一服务 一般来说服务的启动有两个阶段,一个是开机是否启动,以及现在是否启动 systemctl【command】【unit】 command主要有&…...

【GStreamer 】 TX1中CPU和GPU解码显示海康相机RTSP流
大家好,我是虎哥,今天找了一套海康的相机,想后续测试一下DeepStream用网络相机RTSP流做输入看看后续目标识别和分类。但是还是想先实时看看视频,当然,可以选择VLC去查看,顺道我也用GStreamer 来测试了一下&…...

匿名内部类、Lambda表达式、方法引用对比分析
文章目录一、匿名内部类1. 语法格式2. 使用方法① 传统方式② 匿名内部类方式二、Lambda表达式1. 语法格式2. 使用方法① 匿名内部类方式② Lambda表达式方式三、方法引用1. 语法格式2. 使用方法① 类型的静态方法引用② 类型的构造方法引用③ 类型的实例方法引用④ 对象的实例…...

ESXi主机CVE-2021-21972漏洞复现安全处置建议
一、漏洞简介 vSphere 是 VMware 推出的虚拟化平台套件,包含 ESXi、vCenter Server 等一系列的软件。其中 vCenter Server 为 ESXi 的控制中心,可从单一控制点统一管理数据中心的所有 vSphere 主机和虚拟机。 vSphere Client(HTML5…...

研报精选230217
目录 【行业230217毕马威】奢侈品行业新气象【行业230217国信证券】医药生物行业2023年2月投资策略:持续关注疫后复苏和创新两大主线【行业230217国金证券】航空锻造:稳定格局筑专业化壁垒,顺势而为拓产业链深度【个股230217西南证券_招商轮船…...

c++11 标准模板(STL)(std::unordered_set)(一)
定义于头文件 <unordered_set> template< class Key, class Hash std::hash<Key>, class KeyEqual std::equal_to<Key>, class Allocator std::allocator<Key> > class unordered_set;(1)(C11 起)namespace pmr { templ…...

【C语言进阶】你听说过柔性数组吗?
👦个人主页:Weraphael ✍🏻作者简介:目前是C语言学习者 ✈️专栏:C语言航路 🐋 希望大家多多支持,咱一起进步!😁 如果文章对你有帮助的话 欢迎 评论💬 点赞&a…...

[LeetCode]1237. 找出给定方程的正整数解
题目链接:https://leetcode.cn/problems/find-positive-integer-solution-for-a-given-equation/description/ 题目描述: 样例1: 输入:function_id 1, z 5 输出:[[1,4],[2,3],[3,2],[4,1]] 解释:functi…...

【路径规划】基于A*算法和Dijkstra算法的路径规划(Python代码实现)
👨🎓个人主页:研学社的博客💥💥💞💞欢迎来到本博客❤️❤️💥💥🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密…...

蓝桥杯 stm32 PWM 设置占空比
本文代码使用 HAL 库。 文章目录 前言一、创建CubeMX 工程 ,占空比分析:二、相关函数:1. 获取 CNT函数2.设置CNT为 0 函数(计算器清零)3.开启TIM2_CH1的输入捕获中断函数4.TIM 回调函数三、设置上升沿,下降沿四、在lcd上显示 R40 占空比 详细代码五、设置占空比,输出 PW…...

React 合成事件理解
1 事件三个阶段 捕获、目标、处理 (具体百度,后面有空补全)2import React from "react";class Test extends React.Component {parentRef;childRef;constructor(props) {super(props);this.parentRef React.createRef();this.chil…...

202302|读书笔记——国图点滴
杂志剪影|看一本赚一本系列 anywhere 随心而行随心而动,极简相生复古文艺 热情洋溢 色彩斑斓 极致优雅 深邃魅力 新生绽放 灿若星空 异彩纷呈含苞待放 惊艳绽放 爱在云端 空中婚礼 暗夜浪漫 策马逐梦橘影相映 浆果红唇 梦幻无暇 永无止境浮光掠影 微酥清风低调奢华…...

Linux 操作系统原理 — NUMA 架构中的多线程调度开销与性能优化
目录 文章目录 目录前言NUMA 架构中的多线程性能开销1、跨 Node 的 Memory 访问开销2、跨 Core 的多线程 Cache 同步开销3、多线程上下文切换开销4、多线程模式切换开销5、中断处理的开销6、TLB 缓存失效的开销7、内存拷贝的开销NUMA 架构中的性能优化:使用多核编程代替多线程…...

OpenGL - 如何理解 VAO 与 VBO 之间的关系
系列文章目录 LearnOpenGL 笔记 - 入门 01 OpenGLLearnOpenGL 笔记 - 入门 02 创建窗口LearnOpenGL 笔记 - 入门 03 你好,窗口LearnOpenGL 笔记 - 入门 04 你好,三角形 文章目录系列文章目录1. 前言2. 渲染管线的入口 - 顶点着色器2.1 顶点着色器处理过…...

Linux中sed的使用
语法: sed [选项] [sed内置命令字符] [输入文件]选项: 参数说明-n取消默认色的输出常与sed内置命令p一起使用-i直接将修改结果写入文件,不用-i,sed修改的是内存数据-e多次编译,不需要管道符了-r支持正则扩展 sed的内…...

[软件工程导论(第六版)]第1章 软件工程学概述(复习笔记)
文章目录1.1 软件危机1.1.1 软件危机的介绍1.1.2 产生软件危机的原因1.1.3 消除软件危机的途径1.2 软件工程1.2.1 软件工程的介绍1.2.2 软件工程的基本原理1.2.3 软件工程方法学1.3 软件生命周期组成1.4 软件过程概念1.4.1 瀑布模型1.4.2 快速原型模型1.4.3 增量模型1.4.4 螺旋…...

ISP相关
Internet Service Provider,网络提供商/运营商,如电信、联通、移动等。 1. 与ISP互联的出口带宽 IDC或云提供商会与各运营商互联,互联的具体带宽数值一旦泄露,就会被恶意的攻击者利用。例如,若DDos攻击者知道了被攻击…...

vTESTstudio - VT System CAPL Functions - VT2004(续1)
成熟,就是某一个突如其来的时刻,把你的骄傲狠狠的踩到地上,任其开成花或者烂成泥。vtsStartStimulation - 启动激励输出功能:自动激励输出注意:在启动激励输出之前,一定要设置好输出模式Target:目标通道变量空间名称,例…...