当前位置: 首页 > news >正文

【设计模式】访问者模式

访问者模式

访问者模式被称为是最复杂的设计模式,比较难理解并且使用频率不高。

在 GoF 的《设计模式》⼀书中,访问者者模式(Visitor Design Pattern)是这么定义的:

Allows for one or more operation to be applied to a set of objects at runtime, decoupling the operations from the object structure.

允许⼀个或者多个操作应⽤到⼀组对象上,解耦操作和对象本⾝。
访问者模式是一种将数据结构和数据操作分离的设计模式,属于行为型模式。

访问者模式的基本思想是: 假设系统中有一个由许多对象构成的对象结构(元素),这些对象的类都提供一个accept()方法用来接受访问者对象的访问,不同的访问者访问同一对象可以产生不同的数据结果(访问者其实就是一个拥有visit()方法的接口) 。accept()方法可以接收不同的访问者对象,然后在其内部将自己(元素)转发到访问者对象的visit()方法内。

访问者模式的核心是解耦数据结构和数据操作,使得对元素的操作具备良好的扩展性。可以通过扩展不同的访问者来实现对同一元素集的不同操作。

如果你的系统中只是对单个对象(类)进行操作或者对多个类进行一种操作,那么就没必要使用访问者模式了。运用访问者模式是为了方便后续扩展操作类型,在对对象集(多个类对象)扩展操作的时候可以不需要修改所有类的代码。

当系统中存在类型数目稳定(固定)的一类数据结构时,可以通过访问者模式方便地实现对该类型所有数据结构的不同操作。

访问者模式类图

在这里插入图片描述

主要包含四个角色 :
Visitor 抽象访问者:接口或者抽象类,它定义了对每一个可访问元素(Visitable Element)访问的行为,它的参数就是可以访问的元素,它的方法个数理论上来讲与元素个数(Element的实现类个数)是一样的,从这点不难看出,访问者模式要求元素类的个数不能改变(不能改变的意思是说,如果元素类的个数经常改变,则说明不适合使用访问者模式)。
ConcreteVisitor:具体的访问者,实现对每一个元素的具体操作。
Element 抽象元素:元素接口,它定义了一个接受访问者(accept)的方法,其意义是指,每一个元素都要可以被访问者访问。
ConcreteElement:具体的元素类,它提供接受访问者的具体实现,而这个具体的实现,通常情况下是调用访问者提供的访问该元素类的方法。

代码示例

我们使用访问者模式模拟一个处理不同类型文件的场景
假设我们有三类文件,PDF,EXCEL,WORD,我们需要从三种文件中提取信息存到到自己的系统里(假设需要导入到自己的一个txt文件),然后还需要对三类文件都进行压缩等一系列功能

将不同文件类型定义为抽象元素(这是一个稳定的数据结构), 对文件的操作定义为访问者,代码如下 :

public abstract class ResourceFile {private String name;protected ResourceFile(String name) {this.name = name;}abstract void accept(Vistor vistor);}
public class PDFFile extends ResourceFile {protected PDFFile(String name) {super(name);}@Overridevoid accept(Vistor vistor) {vistor.visit(this);}
}public class ExcelFile extends ResourceFile{protected ExcelFile(String name) {super(name);}@Overridevoid accept(Vistor vistor) {vistor.visit(this);}
}public class WordFile extends ResourceFile{public WordFile(String name) {super(name);}@Overridevoid accept(Vistor vistor) {vistor.visit(this);}
}
public interface Vistor {void visit(PDFFile file);void visit(ExcelFile file);void visit(WordFile file);}
public class CompressionVistor implements Vistor{@Overridepublic void visit(PDFFile file) {System.out.println("压缩pdf文件");}@Overridepublic void visit(ExcelFile file) {System.out.println("压缩excel文件");}@Overridepublic void visit(WordFile file) {System.out.println("压缩word文件");}
}
public class ExtractVistor implements Vistor{@Overridepublic void visit(PDFFile file) {System.out.println("提取pdf文字内容");}@Overridepublic void visit(ExcelFile file) {System.out.println("提取excel文字内容");}@Overridepublic void visit(WordFile file) {System.out.println("提取word文字内容");}
}
public class Test {private static final List<ResourceFile> resourceFileList = new ArrayList<>();static {resourceFileList.add(new PDFFile("设计模式.pdf"));resourceFileList.add(new ExcelFile("Data.excel"));resourceFileList.add(new WordFile("笔记.doc"));}public static void main(String[] args) {for (ResourceFile resourceFile: resourceFileList) {resourceFile.accept(new CompressionVistor());}for (ResourceFile resourceFile: resourceFileList) {resourceFile.accept(new ExtractVistor());}}}

Double Dispatch

静态分派

静态分派(Static Dispatch)就是按照变量的静态类型(变量被声明时的类型)进行分派,从而确定方法的执行版本,静态分派在编译时就可以确定方法的版本,典型例子就是java的方法重载
java在静态分派的时候,我们可以根据多个判断依据(即参数个数和参数类型)判断使用哪个方法,所以java是静态多分派的语言

动态分派

动态分派,不是在编译期确定方法版本,而是在运行时才能确定

Single Dispatch,指的是我们仅仅需要根据对象运行时的类型来决定执行哪个对象的方法

Double Dispatch,指的是我们需要根据对象的运行时类型和参数的运行时类型来决定执行哪个对象的哪个方法 (二者区别主要在于是否可以根据方法参数运行时的类型来判断执行对象的哪个方法)

当前主流的⾯向对象编程语⾔(⽐如,Java、C++、C#)都只⽀持 Single Dispatch,不⽀持 Double Dispatch。

以Java为例,Java⽀持多态,代码可以在运⾏时获得对象的实际类型,然后根据实际类型决定调⽤哪个对象的方法。 Java 也⽀持方法重载,但 Java 设计的方法重载的语法规则是在编译时,根据传递进函数的参数的声明类型,来决定调⽤哪个重载方法。也就是说,具体执⾏哪个对象的哪个⽅法,只跟对象的运⾏时类型有关,跟参数的运⾏时类型⽆关。所以,Java 语⾔是 动态单分派的语言。

我们可以看下具体的例子 :

public class ParentClass {public void method() {System.out.println("ParentClass 执行method方法");}}public class SonClass extends ParentClass{@Overridepublic void method() {System.out.println("SonClass 执行method方法");}
}
public class SingleDispatch {public void method(ParentClass parentClass) {parentClass.method();}public void print(ParentClass parentClass) {System.out.println("打印parentClass");}public void print(SonClass sonClass) {System.out.println("打印sonClass");}
}
public class Test {public static void main(String[] args) {ParentClass s = new SonClass();SingleDispatch singleDispatch = new SingleDispatch();singleDispatch.method(s);//执⾏哪个对象的⽅法,由对象的实际类型决定(多态)singleDispatch.print(s);//执⾏对象的哪个⽅法,由参数对象的声明类型决定,这里声明的时ParentClass类型}}

在这里插入图片描述

动态双分派的语言不需要访问者模式

假设 Java 语⾔⽀持 动态双分派,那么下面的代码就可以编译通过,正常执行了。

public class ExtractExecutor {public void extract(PDFFile file) {System.out.println("提取pdf文字内容");}public void extract(WordFile file) {System.out.println("提取word文字内容");}public void extract(ExcelFile file) {System.out.println("提取excel文字内容");}}
    public static void main(String[] args) {ExtractExecutor extractExecutor = new ExtractExecutor();for (ResourceFile resourceFile: resourceFileList) {//这里会编译报错: Cannot resolve method 'extract(ResourceFile)'extractExecutor.extract(resourceFile);}}

代码会在运⾏时,根据参数(resourceFile)的实际类型(PDFFile、ExcelFile、WordFile),来决定调用extract()的三个重载方法中的哪⼀个,也就不需要访问者模式了。

访问者模式中的伪动态双分派

所谓的动态双分派就是在运行时根据对象和参数的运行时类型去判断调用哪个一个对象的哪个方法。访问者模式通过进行两次动态单分派来达到这个效果。

for (ResourceFile resourceFile: resourceFileList) {resourceFile.accept(new ExtractVistor());}
  @Overridevoid accept(Vistor vistor) {vistor.visit(this);}

当调用accept()方法的时候, 根据resourceFile的实际类型决定调用哪个文件的accept()方法;
在执行accept()方法的时候,根据vistor的示例类型来决定调用哪个Vistor的visist方法,此时的this的类型就是这个类的静态类型,这是在编译期就确定的,所以也可以确定是调用的哪个重载方法

通过工厂模式实现上述功能

上述的例子,如果对文件的操作也比较固定,也可以使用工厂模式来实现,定义⼀个包含 extract() 接⼝的Executor接⼝。PdfExtractExecutor、ExcelExtractExecutor、WordExtractExecutor 类实现 Executor接⼝,完成对各自⽂件的⽂本内容抽取。然后再提供一个ExtractExecutorFactory ⼯⼚类根据不同的⽂件类型,返回不同的 Executor。

public abstract class ResourceFile {private String name;protected ResourceFile(String name) {this.name = name;}abstract String getType();
}
public class PDFFile extends ResourceFile {protected PDFFile(String name) {super(name);}@OverrideString getType() {return "PDF";}}
public interface Executor {void extract(ResourceFile file);
}
//省略了WordExtractExecutor,ExcelExtractExecutor的代码
public class PDFExtractExecutor implements Executor{@Overridepublic void extract(ResourceFile file) {System.out.println("提取pdf的内容");}
}
public class ExtractExecutorFactory {private static Map<String, Executor> map = new HashMap<>();static {map.put("PDF", new PDFExtractExecutor());
//        map.put("EXCEL", new ExeclExtractExecutor());
//        map.put("WORD", new WordExtractExecutor());}public static Executor getExecutor(ResourceFile file) {return map.get(file.getType());}}

访问者模式在源码中的应用

Java 7 版本后,Files 类提供了 walkFileTree() 方法,该方法可以很容易的对目录下的所有文件进行遍历,需要 Path、FileVisitor 两个参数。其中,Path 是要遍历文件的路径,FileVisitor 则可以看成一个文件访问器。源码如下。

package java.nio.file;
public final class Files {...public static Path walkFileTree(Path start, FileVisitor<? super Path> visitor)throws IOException{return walkFileTree(start,EnumSet.noneOf(FileVisitOption.class),Integer.MAX_VALUE,visitor);}...
}

FileVisitor 提供了递归遍历文件树的支持,这个接口的方法表示了遍历过程中的关键过程,允许在文件被访问、目录将被访问、目录已被访问、发生错误等过程中进行控制。换句话说,这个接口在文件被访问前、访问中和访问后,以及产生错误的时候都有相应的钩子程序进行处理。

FileVisitor 主要提供了 4 个方法,且返回结果的都是 FileVisitResult 对象值,用于决定当前操作完成后接下来该如何处理。FileVisitResult 是一个枚举类,代表返回之后的一些后续操作。

package java.nio.file;import java.nio.file.attribute.BasicFileAttributes;
import java.io.IOException;
public interface FileVisitor<T> {FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs)throws IOException;FileVisitResult visitFile(T file, BasicFileAttributes attrs)throws IOException;FileVisitResult visitFileFailed(T file, IOException exc)throws IOException;FileVisitResult postVisitDirectory(T dir, IOException exc)throws IOException;
}package java.nio.file;public enum FileVisitResult {CONTINUE,TERMINATE,SKIP_SUBTREE,SKIP_SIBLINGS;
}

FileVisitResult 主要包含 4 个常见的操作。

  • FileVisitResult.CONTINUE:这个访问结果表示当前的遍历过程将会继续。
  • FileVisitResult.SKIP_SIBLINGS:这个访问结果表示当前的遍历过程将会继续,但是要忽略当前文件/目录的兄弟节点。
  • FileVisitResult.SKIP_SUBTREE:这个访问结果表示当前的遍历过程将会继续,但是要忽略当前目录下的所有节点。
  • FileVisitResult.TERMINATE:这个访问结果表示当前的遍历过程将会停止。

通过访问者去遍历文件树会比较方便,比如查找文件夹内符合某个条件的文件或者某一天内所创建的文件,这个类中都提供了相对应的方法。它的实现也非常简单,代码如下

public class SimpleFileVisitor<T> implements FileVisitor<T> {protected SimpleFileVisitor() {}@Overridepublic FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs)throws IOException{Objects.requireNonNull(dir);Objects.requireNonNull(attrs);return FileVisitResult.CONTINUE;}@Overridepublic FileVisitResult visitFile(T file, BasicFileAttributes attrs)throws IOException{Objects.requireNonNull(file);Objects.requireNonNull(attrs);return FileVisitResult.CONTINUE;}@Overridepublic FileVisitResult visitFileFailed(T file, IOException exc)throws IOException{Objects.requireNonNull(file);throw exc;}@Overridepublic FileVisitResult postVisitDirectory(T dir, IOException exc)throws IOException{Objects.requireNonNull(dir);if (exc != null)throw exc;return FileVisitResult.CONTINUE;}
}

一开始觉得这里的设计比较多余,后来仔细想了下,在不同场景下我们对文件树的遍历要求是不一样的,通过访问者模式,用户可以方便的定义自己的遍历操作

比方说在JavacPathFileManager里就重写了preVisitDirectoryvisitFile方法

    Files.walkFileTree(packageDir, opts, maxDepth,new SimpleFileVisitor<Path>() {@Overridepublic FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {Path name = dir.getFileName();if (name == null || SourceVersion.isIdentifier(name.toString())) // JSR 292?return FileVisitResult.CONTINUE;elsereturn FileVisitResult.SKIP_SUBTREE;}@Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {if (attrs.isRegularFile() && kinds.contains(getKind(file.getFileName().toString()))) {JavaFileObject fe =PathFileObject.createDirectoryPathFileObject(JavacPathFileManager.this, file, pathDir);results.append(fe);}return FileVisitResult.CONTINUE;}});

总结

简单来说,访问者模式就是封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新操作。

访问者模式适用场景 :

  1. 数据结构稳定,但是作用于数据结构的操作经常变化
  2. 需要数据结构与数据操作分离
  3. 需要对不同数据类型(元素)进行操作,但是有不使用if.. else ..判断具体类型

优点:

  1. 使得数据结构和作用于结构上的操作解耦,使得操作集合可以独立变化。
  2. 扩展性好,添加新的操作或者说访问者会非常容易。

缺点:

  1. 增加新的元素类型会非常困难,每次新增元素类型,则访问者类必须增加对应元素类型的操作
  2. 违反了依赖倒置原则,访问者依赖的是具体元素类型,而不是抽象
  3. 变更元素的属性可能会导致对应的访问者类也需要修改

相关文章:

【设计模式】访问者模式

访问者模式 访问者模式被称为是最复杂的设计模式&#xff0c;比较难理解并且使用频率不高。 在 GoF 的《设计模式》⼀书中&#xff0c;访问者者模式(Visitor Design Pattern&#xff09;是这么定义的&#xff1a; Allows for one or more operation to be applied to a set o…...

蓝桥杯刷题冲刺 | 倒计时27天

作者&#xff1a;指针不指南吗 专栏&#xff1a;蓝桥杯倒计时冲刺 &#x1f43e;马上就要蓝桥杯了&#xff0c;最后的这几天尤为重要&#xff0c;不可懈怠哦&#x1f43e; 文章目录1.递增序列2.等差素数列3.七段码4.亲戚5.连通块中点的数量1.递增序列 题目 链接&#xff1a;&am…...

RV1126_python人脸识别Retinaface+MobilefaceNet

RV1126_python人脸识别Retinaface+MobilefaceNet RV1126 具备RKNN 模块支持大部分如Pytorch、MXNet、Caffe、tensorflow、keras、onnx等常见框架,而且量化部署使用RKNN-toolkit非常方便。以下介绍通过RV1126实现的人脸识别过程。 首先人脸识别需要先做人脸检测>>人脸校正…...

HBase---HBase基础语法

HBase基础语法 文章目录HBase基础语法基本操作进入 HBase 客户端命令行查看命名空间查看命名空间下的表创建命名空间创建表查看表描述禁用/启用删除表新增列族删除列族更改列族存储版本的限制put 增加数据get 查看数据get条件查询删除指定列族下的指定列删除指定行全表扫描全表…...

2023年,PMP有多少含金量呢?

其实围绕以PMP含金量为中心的这个类似的小问题我好像也已经写了不少文章了。首先我肯定PMP的含金量&#xff0c;不管有多少质疑&#xff0c;这的确是事实。因为就是看中了他的价值考的&#xff0c;并且在项目的执行上收获了很多。 ​具体的可以看我接下来谈的PMP的价值&#x…...

vue动态路由

import Vue from vue import Router from vue-router import layout from ../components/layout Vue.use(Router) // 动态路由 export const asyncRouterMap = [ { path: /home, component: layout, name: home, meta: { title: 首页, icon: el-ic…...

被骗进一个很隐蔽的外包公司,入职一个月才发现,已经有了社保记录,简历污了,以后面试有影响吗?...

职场的套路防不胜防&#xff0c;一不留神就会掉坑&#xff0c;一位网友就被“骗”进了外包公司&#xff0c;他说公司非常隐蔽&#xff0c;入职一个月才发现是外包&#xff0c;但已经有了社保记录&#xff0c;简历污了&#xff0c;不知道对以后面试有影响吗&#xff1f;楼主说&a…...

华为OD机试 -租车骑绿岛(Java) | 机试题+算法思路+考点+代码解析 【2023】

租车骑绿岛 题目 部门组织绿岛骑行团建活动。租用公共双人自行车骑行,每辆自行车最多坐两人、做大载重M。 给出部门每个人的体重,请问最多需要租用多少双人自行车。 输入 第一行两个数字m、n,自行车限重m,代表部门总人数n。 第二行,n个数字,代表每个人的体重。体重都…...

【Java|基础篇】用思维导图理解逻辑控制

文章目录顺序结构分支结构if单分支语句if else双分支语句if else if else多分支语句switch语句循环语句for循环while循环do while循环continuebreak总结顺序结构 顺序结构是指代码按照从上往下的顺序依次执行 分支结构 选择语句是条件成立时,才会执行的语句.共有三种.分为是if…...

Go单元测试基础

Go单元测试基础1.go test工具2.单元测试函数3.go test -v/go test -run4.跳过某些测试用例5.子测试6.表格驱动测试7.并行测试8.使用工具生成测试代码9.测试覆盖率1.go test工具 Go语言中的测试依赖go test命令。编写测试代码和编写普通的Go代码过程是类似的&#xff0c;并不需…...

华为OD机试 -执行时长(Java) | 机试题+算法思路+考点+代码解析 【2023】

执行时长 题目 为了充分发挥GPU算力,需要尽可能多的将任务交给GPU执行,现在有一个任务数组,数组元素表示在这1秒内新增的任务个数且每秒都有新增任务,假设GPU最多一次执行n个任务,一次执行耗时1秒,在保证GPU不空闲情况下,最少需要多长时间执行完成 输入描述: 第一个…...

互联网检测服务器

互联网检测服务器 1. 题目要求2. 试题解析1. 题目要求 题目: 为了模拟 Internet 访问测试,请搭建网卡互联网检测服务。 2. 试题解析 根据windows的官方文档,互联网检测服务有专门的域名,通过注册表可以找到检测域名字符串的写法(字符串为www.msftconnecttest.com),具体位…...

YOLO系列模型改进指南

YOLO系列模型改进指南 目前包含yolov5&#xff0c;yolov7&#xff0c;yolov8模型的众多改进方案&#xff0c;效果因数据集和参数而定&#xff0c;仅供参考。 如果需要改进模型&#xff0c;建议baseline和改进模型也不要载入预训练权重&#xff0c;不然的话&#xff0c;他们的起…...

QML- 在QML定义JavaScript资源

在QML定义JavaScript资源一、概述二、后台代码实现文件三、共享JavaScript资源(库)一、概述 QML应用程序的一部分程序逻辑可以用 JavaScript 定义。JavaScript代码可以在QML文档中内联定义&#xff0c;也可以分离到单独的 JavaScript 文件中(在QML中称为JavaScript资源)。 QML…...

php(tp框架)使用七牛云对象存储

图片文件存服务器非常占用存储带宽资源&#xff0c;且用户访问体验也不佳&#xff0c;因此使用一些第三方oss存储就很有必要了。之前lz发布了一篇tp使用阿里云oss的博文。不过阿里oss是收费的。而七牛云提供了一些免费使用额度。所以&#xff0c;这里额外补充一篇。 1.前提准备…...

八大排序算法之插入排序+希尔排序

目录 一.前言(总体简介) 关于插入排序 关于希尔排序: 二.插入排序 函数首部: 算法思路: 算法分析 插入排序代码实现: 插入排序算法的优化前奏: 三.希尔排序(缩小增量排序) 1.算法思想: 2.算法拆分解析 序列分组 分组预排序: 分组预排序的另一种实现方式: 希尔…...

蓝桥杯第十四届蓝桥杯模拟赛第三期考场应对攻略(C/C++)

这里把我的想法和思路写出来&#xff0c;恳请批评指正&#xff01; 目录 考前准备 试题1&#xff1a; 试题2&#xff1a; 试题3&#xff1a; 试题4&#xff1a; 试题5&#xff1a; 试题6&#xff1a; 试题7&#xff1a; 试题8&#xff1a; 试题9&#xff1a; 试题1…...

【数论】最大公约数、约数的个数与约数之和定理

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…...

第28篇:Java日期Calendar类总结(二)

目录 1、获取系统当前时间 2、获取指定日期 3、对象字段类型 4 、对象信息设置 4.1 Set设置...

【Python】字符串 - 集大成篇

目录 1. 不同语言的字符串比较 1.1 C 语言 1.2 C 语言 1.2.1 C 风格字符串 1.2.2 C 风格字符串 1.3 JAVA 1.4 Python 2. Python 字符串 2.1 方法 2.2.1 title () 2.2.2 lower () 2.2.3 upper () 2.2.4 rstrip () 2.2.5 lstrip …...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

c++第七天 继承与派生2

这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分&#xff1a;派生类构造函数与析构函数 当创建一个派生类对象时&#xff0c;基类成员是如何初始化的&#xff1f; 1.当派生类对象创建的时候&#xff0c;基类成员的初始化顺序 …...

手机平板能效生态设计指令EU 2023/1670标准解读

手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读&#xff0c;综合法规核心要求、最新修正及企业合规要点&#xff1a; 一、法规背景与目标 生效与强制时间 发布于2023年8月31日&#xff08;OJ公报&…...

MySQL 主从同步异常处理

阅读原文&#xff1a;https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主&#xff0c;遇到的这个错误&#xff1a; Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一&#xff0c;通常表示&#xff…...

云原生安全实战:API网关Envoy的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关 作为微服务架构的统一入口&#xff0c;负责路由转发、安全控制、流量管理等核心功能。 2. Envoy 由Lyft开源的高性能云原生…...

高效的后台管理系统——可进行二次开发

随着互联网技术的迅猛发展&#xff0c;企业的数字化管理变得愈加重要。后台管理系统作为数据存储与业务管理的核心&#xff0c;成为了现代企业不可或缺的一部分。今天我们要介绍的是一款名为 若依后台管理框架 的系统&#xff0c;它不仅支持跨平台应用&#xff0c;还能提供丰富…...