设计模式之迭代器模式与命令模式详解和应用
目录
- 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…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...

微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...

SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...

招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...