设计模式精讲:掌握工厂方法与抽象工厂的精髓

设计模式精讲:掌握工厂方法与抽象工厂的精髓

  • 一、引言:如何学习设计模式?
  • 二、工厂方法(也叫工厂模式)
    • 2.1、代码结构
    • 2.2、符合的设计原则
    • 2.3、小结
  • 三、抽象工厂
    • 3.1、代码结构
    • 3.2、符合的设计原则
    • 3.3、小结
  • 总结

一、引言:如何学习设计模式?

学习设计模式最主要要抓住一点:就是怎么分析这个稳定点和变化点。自己实现一个框架,或者是实现一个具体的小功能,本质上分析问题的思路都是一样的,首先要去把稳定点给它抽象出来,然后针对这个变化点想着怎么去扩展它。所以这里还是要反复的介绍怎么分析这个稳定点和变化点;具体不同的设计模式是怎么来处理这个扩展(就是扩展的问题);稳定点它是怎么处理的;用C++的语言特性是怎么去解决这些问题的;沿着这个思路去学习。

前面已经介绍了设计模式当中的模板方法、观察的模式、以及策略模式,这里再次强调以下学习、掌握设计模式的学习步骤。

  • 首先,需要来了解设计模式解决了什么问题。本质上是分析它的稳定点和变化点,实际在做具体功能开发的时候也需要去抽象具体的稳定点以及想办法去扩展变化点,这样在实际开发过程当中,尽量写少量的代码去应对未来需求的变化。
  • 第二点,设计模式的代码结构是什么。需要培养一个看代码、看一些框架或者看项目代码结构的时候马上能够反应出来使用了什么设计模式,或者它符合什么设计原则,从而可以推断出代码具体的意图。熟悉实现具体设计模式的代码结构能够帮助我们对一个代码有一个敏感度,以便能够快速的进行推断和反应。
  • 第三点,看这些设计模式符合了哪些设计原则。因为设计模式是由设计原则推导过来的,所以可以按照这一个设计模式的产生的流程重新去思考这一个问题,能够帮助我们去很好的去设计我们的代码。相信很多人在具体的工作当中都有自己不同的一些设计方式,它不一定符合某一些设计模式,未来大家应对的某些需求也会自己去设计一个框架,所以可以思考它符合哪些设计原则。
  • 第四点,如何在上面扩展代码。尤其是对于初学者或刚刚参加工作的朋友们,对这个扩展代码一定要非常的清楚,就是如果在这个设计模式的基础上要修改哪些代码,这个是必须要掌握的。
  • 第五点,按照自己的需求或者自己的项目以及自己的工作场景进行一个联系,哪些需求变化可以使用设计模式;在看开源框架的时候也可以去看一下它是怎么解决这一个问题的。记住几个关键设计模式的一些典型应用场景能够帮助我们快速的反应;当具体需求来了知道该怎么使用某一些设计模式。
学习步骤
设计模式解决什么问题
稳定点
变化点
设计模式的代码结构是什么
设计模式符合哪些设计原则
如何在上面扩展代码
该设计模式有哪些典型应用场景
联系工作场景
开源框架

这个就是设计模式具体的学习步骤。

二、工厂方法(也叫工厂模式)

首先从定义出发,工厂方法的定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使得一个类的实例化延迟到子类

接下来就要分析它解决了什么问题。它的定义不需要特别的去关注,也不要记这个定义,主要分析这个定义当中的稳定点和变化点。

  • 稳定点:创建同类对象的接口,并且同类对象有一个相同的职责。要提供同类对象的一个接口,同类对象只有一个相同的职责(职责就是功能的意思)。
  • 变化点:对象的拓展。同一类对象会越来越多,要进行对象的扩展。

2.1、代码结构

举个例子来帮助理解:

实现一个导出数据的接口,让客户选择数据的导出方式。

这个的职责是导出数据,这里面的导出数据有很多方式可以让用户选择,即同类对象都有导出功能,而且都是导出数据。因此,要创建一个对象接口以满足同类对象有相同的职责(职责就是导出数据)。

不使用设计模式的时候,首先要使用设计原则,注意到的是“导出数据”是一个职责,马上要想到接口,对于这种问题想都不用想就是要考虑用接口去封装它,因为有多个不同导出数据的接口,就要用统一的接口,这个接口就代表它有一个什么样的功能(即导出功能),马上就可以写出这样的一个语句:

// 实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式txt 后面可能扩展excel格式csv
class IExport {
public:virtual bool Export(const std::string &data) = 0;virtual ~IExport(){}
};

就是导出这个具体的数据有很多格式,比如说有xml,有json,有txt,还有excel格式csv等等。然后尝试实现接口:继承IExport ,实现Export()方法。

#include <string>
// 实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式txt 后面可能扩展excel格式csv
class IExport {
public:virtual bool Export(const std::string &data) = 0;virtual ~IExport(){}
};class ExportXml : public IExport {
public:virtual bool Export(const std::string &data) {return true;}
};class ExportJson : public IExport {
public:virtual bool Export(const std::string &data) {return true;}
};
// csv
class ExportTxt : public IExport {
public:virtual bool Export(const std::string &data) {return true;}
};// class ExportCSV : public IExport {
// public:
//     virtual bool Export(const std::string &data) {
//         return true;
//     }
// };// =====1
int main() {std::string choose/* = */;if (choose == "txt") {/***/IExport *e = new ExportTxt();/***/e->Export("hello world");} else if (choose == "json") {/***/IExport *e = new ExportJson();/***/e->Export("hello world");} else if (choose == "xml") {IExport *e = new ExportXml();e->Export("hello world");} else if (choose == "csv") {IExport *e = new ExportXml();e->Export("hello world");}
}

实现导出功能,实现IExport类就可以导出为xml、json、txt等格式,因为在这里只有一个导出职责(导出功能),都是一样的,同样的接口Export把它实现好,未来可能会增加CSV也可以实现一下。接下来让用户选择数据的导出方式,int main() 就要实现这个功能了。在这里按用户的输入判断,然后new出来这个数据,然后再把它进行Export。这个是没有使用设计模式的时候,仅仅考虑面向接口编程写出来的这样的一个代码。

接下来看一下符合设计模式是怎么进行开发的,其实这里创建同类对象的接口可以用一个工厂接口来实现,有相同的职责可以用一个具体的职责接口来实现,也就是说这里应该要抽象出两个接口:一个是对象产生的接口,一个是具体的职责的接口。要理解这句话,先思考一个问题:

为什么要有工厂模式?

再来了解一下为什么在这里面要用两个接口,而不直接new对象来使用?刚刚举的例子,有一个业务可能没注意到,主要的原因是没有表现出来,因为通常如果使用模式的时候,new的对象不是直接用一个对象这么简单,new完之后还要去有复杂的构造流程。

设计模式通常是要解决创建过程比较复杂,而且希望对外隐藏这些细节的场景,也就是说某一个用户只使用需要使用的功能。比如说导出JSON数据除了要去把JSON库导出来(加载JSON库)可能还需要去调用一些配置参数(配置这个JSON的参数),还可能要进行初始化一些数据,把这些流程都封装起来,放到某一个对象的JSON导出的接口中,那么对于用户而言,只需要知道用JSON导出,用户根本不需要关注还要加载一个库、配置一些参数、初始化一些值才能够去使用它的导出功能。

当创建过程比较复杂,而用户只需要关注他的职责,并不关注他的创建过程,比较复杂的这个流程用户不需要知道,这种时候需要使用工厂方法模式。举个例子,比如说连接池、线程池等,使用连接池通常只需要把一个任务push进去就行了,对于用户而言,只需要有一个push的操作就行了,往里面去push后会自动帮用户完成;如果真正把线程池封装的好,那么对于用户而言,应该只需要知道有一个push接口就行了。都知道线程池要去构建它要初始化(这个把线程加载进来,把线程初始化好),把一些数据初始化,然后把一些入口函数初始化等等,这里面有复杂的构造流程,这些构造流程对于用户而言没什么用,用户根本不需要关注这些东西,用户只需要push任务,对于一个正确的封装者(做功能开发、做功能抽象的人)应该是让用户知道的越少越好。

要点:解决创建过程比较复杂,希望对外隐藏这些细节的场景。

  • 比如连接池、线程池
  • 隐藏对象真实类型;
  • 对象创建会有很多参数来决定如何创建;
  • 创建对象有复杂的依赖关系。

工厂方法实现的代码:

#include <string>
// 实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式txt 后面可能扩展excel格式csv
class IExport {
public:virtual bool Export(const std::string &data) = 0;virtual ~IExport(){}
};class ExportXml : public IExport {
public:virtual bool Export(const std::string &data) {return true;}
};class ExportJson : public IExport {
public:virtual bool Export(const std::string &data) {return true;}
};class ExportTxt : public IExport {
public:virtual bool Export(const std::string &data) {return true;}
};class ExportCSV : public IExport {
public:virtual bool Export(const std::string &data) {return true;}
};class IExportFactory {
public:IExportFactory() {_export = nullptr;}virtual ~IExportFactory() {if (_export) {delete _export;_export = nullptr;}}bool Export(const std::string &data) {if (_export == nullptr) {_export = NewExport();}return _export->Export(data);}
protected:virtual IExport * NewExport(/* ... */) = 0;
private:IExport* _export;
};class ExportXmlFactory : public IExportFactory {
protected:virtual IExport * NewExport(/* ... */) {// 可能有其它操作,或者许多参数IExport * temp = new ExportXml();// 可能之后有什么操作return temp;}
};
class ExportJsonFactory : public IExportFactory {
protected:virtual IExport * NewExport(/* ... */) {// 可能有其它操作,或者许多参数IExport * temp = new ExportJson;// 可能之后有什么操作return temp;}
};
class ExportTxtFactory : public IExportFactory {
protected:IExport * NewExport(/* ... */) {// 可能有其它操作,或者许多参数IExport * temp = new ExportTxt;// 可能之后有什么操作return temp;}
};class ExportCSVFactory : public IExportFactory {
protected:virtual IExport * NewExport(/* ... */) {// 可能有其它操作,或者许多参数IExport * temp = new ExportCSV;// 可能之后有什么操作return temp;}
};int main () {IExportFactory *factory = new ExportCSVFactory();factory->Export("hello world");return 0;
}

为了实现封装出复杂的对象的构建过程,给了一个对象创建的一个接口IExportFactory ,那么这里的IExport 是功能接口(具体到底实现了一个什么功能)。具体的构造流程在NewExport()中实现,用户不会关注这个的实现,用户只关注Export功能(导出功能)。知道这些接口之后,还需要不同对象的构造,IExportFactory 是基类,使用ExportTxtFactory ExportCSVFactory ExportXmlFactory 等实现不同的导出对象,复杂的操作流程就在NewExport中实现。最后就是在main ()中使用它。

代码结构:

  • 对象创建接口。
  • 功能接口。
  • 对象扩展。
  • 多态调用的使用方式。

2.2、符合的设计原则

(1)最小知道原则。
(2)面向接口原则。

用户知道的越少越好,让用户只需要知道最需要的东西就行;想让用户知道的越少就要面向接口编程,把用户只关注的行为抽象成接口。

需要哪些接口?

  1. 具体的职责类的功能接口。简单来说就是提供了一个什么功能给用户,示例中用户只需要有一个导出的功能,只要给用户这样一个导出接口,用户只关注一个导出接口就行了,即功能接口是做什么事情的用户要知道。
  2. 对象创建接口。虽然用户不关注,但是要知道怎么去创建;就是有一个具体的对象,到底用户应该用什么东西来实现这个功能,比如说是用JSON来实现这个导出功能、用txt来实现这个导出功能、用CSV来现这个导出功能,就需要一个对象创建的接口;这个对象创建的接口就是所说的工厂接口。

2.3、小结

稳定点都是用抽象去解决,抽象那些万成不变的东西,具体可以用接口来实现。通过分析稳定点,发现要有一个创建同类对象的一个职责接口以及一个功能接口,这两个东西是稳定点,需要注意这个功能接口对于用户而言是不可见的,用户不需要关注这一个功能接口,这个功能接口它具体起到一个什么作用可以看到示例中IExportFactory的功能对象创建的流程。IExportFactory只提供了Export,并没有提供创建的流程,创建流程在NewExport()实现。

扩展代码:

  • 实现对象创建接口。
  • 实现功能接口。
  • 多态调用。

本质:延迟到子类来选择实现。

结构图:

Factory
+CreateProduct()
Product
+Operator()
ConcreteProduct1
+Operator()
ConcreteProduct2
+Operator()
ConcreteProduct3
+Operator()

思维导图:
在这里插入图片描述

三、抽象工厂

理解了工厂模式,抽象工厂就非常的简单,它其实就是在工厂模式当中增加了一个多职责,它除了创建同类对象的接口,它还有就是有多个相同的职责。

抽象工厂的定义:提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。

解决了什么问题:

  • 稳定点:创建同类对象的接口,并且同类对象有多个相同的职责。和工厂方法模式唯一的区别是"有多个相同的职责"。
  • 变化点:对象的拓展。和工厂方法模式一样

3.1、代码结构

看一个例子:

实现一个拥有导出导入数据的接口,让客户选择数据的导出导入方式。

跟前面的工厂方法中的例子差不多,只是多了一个导入的功能,并且让用户去选择导入的方式。也就是说某一个对象(比如说CSV),它刚刚只需要有一个导出功能,现在还要有一个导入的功能;同样的,要把这个导入功能职责也要抽象成一个接口。

这个抽象工厂就非常的简单,它的代码结构基本和工厂方法一样的:

  • 对象创建接口。包括创建具体对象,提供多个功能接口来调用。在创建对象接口当中去调用功能接口。
  • 多个功能接口。

抽象工厂在工厂方法上面就多了一个,它是有多个职责的,它有多个功能的。

抽象工厂的代码实现:

#include <string>
// 实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式txt 后面可能扩展excel格式csv
class IExport {
public:virtual bool Export(const std::string &data) = 0;virtual ~IExport(){}
};class ExportXml : public IExport {
public:virtual bool Export(const std::string &data) {return true;}
};class ExportJson : public IExport {
public:virtual bool Export(const std::string &data) {return true;}
};class ExportTxt : public IExport {
public:virtual bool Export(const std::string &data) {return true;}
};class ExportCSV : public IExport {
public:virtual bool Export(const std::string &data) {return true;}
};class IImport {
public:virtual bool Import(const std::string &data) = 0;virtual ~IImport(){}
};class ImportXml : public IImport {
public:virtual bool Import(const std::string &data) {return true;}
};class ImportJson : public IImport {
public:virtual bool Import(const std::string &data) {return true;}
};class ImportTxt : public IImport {
public:virtual bool Import(const std::string &data) {return true;}
};class ImportCSV : public IImport {
public:virtual bool Import(const std::string &data) {// ....return true;}
};class IDataApiFactory {
public:IDataApiFactory() {_export = nullptr;_import = nullptr;}virtual ~IDataApiFactory() {if (_export) {delete _export;_export = nullptr;}if (_import) {delete _import;_import = nullptr;}}bool Export(const std::string &data) {if (_export == nullptr) {_export = NewExport();}return _export->Export(data);}bool Import(const std::string &data) {if (_import == nullptr) {_import = NewImport();}return _import->Import(data);}
protected:virtual IExport * NewExport(/* ... */) = 0;virtual IImport * NewImport(/* ... */) = 0;
private:IExport *_export;IImport *_import;
};class XmlApiFactory : public IDataApiFactory {
protected:virtual IExport * NewExport(/* ... */) {// 可能有其它操作,或者许多参数IExport * temp = new ExportXml;// 可能之后有什么操作return temp;}virtual IImport * NewImport(/* ... */) {// 可能有其它操作,或者许多参数IImport * temp = new ImportXml;// 可能之后有什么操作return temp;}
};class JsonApiFactory : public IDataApiFactory {
protected:virtual IExport * NewExport(/* ... */) {// 可能有其它操作,或者许多参数IExport * temp = new ExportJson;// 可能之后有什么操作return temp;}virtual IImport * NewImport(/* ... */) {// 可能有其它操作,或者许多参数IImport * temp = new ImportJson;// 可能之后有什么操作return temp;}
};
class TxtApiFactory : public IDataApiFactory {
protected:virtual IExport * NewExport(/* ... */) {// 可能有其它操作,或者许多参数IExport * temp = new ExportTxt;// 可能之后有什么操作return temp;}virtual IImport * NewImport(/* ... */) {// 可能有其它操作,或者许多参数IImport * temp = new ImportTxt;// 可能之后有什么操作return temp;}
};class CSVApiFactory : public IDataApiFactory {
protected:virtual IExport * NewExport(/* ... */) {// 可能有其它操作,或者许多参数IExport * temp = new ExportCSV;// 可能之后有什么操作return temp;}virtual IImport * NewImport(/* ... */) {// 可能有其它操作,或者许多参数IImport * temp = new ImportCSV;// 可能之后有什么操作return temp;}
};// 相关性  依赖性    工作当中
int main () {IDataApiFactory *factory = new CSVApiFactory();factory->Import("hello world");factory->Export("hello world");return 0;
}

除了导出接口,还加入了导入接口,分别实现它们的职责。

3.2、符合的设计原则

基本和工厂方法的一样。
(1)最小知道原则。
(2)面向接口原则。

3.3、小结

抽象工厂模式和工厂方法的区别:工厂方法通常一个对象只有一个职责,而抽象工厂模式是一个对象有多个职责

结构图:
在这里插入图片描述
思维导图:
在这里插入图片描述

总结

在本文中,我们深入探讨了设计模式中两个重要的概念:工厂方法和抽象工厂。首先介绍了设计模式的重要性和应用场景,然后重点讲解了工厂方法模式和抽象工厂模式的原理和实现方式。通过详细的代码结构和实例分析,我们揭示了它们如何提供灵活性、可扩展性和可维护性,并如何符合设计原则。最后,我们强调了工厂方法和抽象工厂的精髓,帮助读者深入理解并将其应用于实际项目中,从而提高编程技能和代码质量。
在这里插入图片描述

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

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

相关文章

rust持续学习 COW

COW我第一次看见还以为是奶牛 很奇怪是个啥 后来了解到是clone on write 缩写的&#xff0c;大乌龙啊 这个有两种enum,一种是borrow&#xff0c;一种是own rust中&#xff0c;数据读写经常涉及到所有权 这个borrow&#xff0c;很显然&#xff0c;就是不可变借用了 own就是可以写…

北邮22级信通院数电:Verilog-FPGA(12)第十二周实验(2)彩虹呼吸灯

北邮22信通一枚~ 跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章 持续关注作者 迎接数电实验学习~ 获取更多文章&#xff0c;请访问专栏&#xff1a; 北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客 目录 一.代码部分 二.管脚分配 三.实验效果 一.代…

大势智慧荣获2023光合组织解决方案大赛人工智能赛道标杆奖及争先奖!

近日&#xff0c;2023年第三届光合组织解决方案大赛获奖名单正式公布。大势智慧以基于国产化平台的实景三维全流程解决方案&#xff0c;突破层层选拔&#xff0c;最终荣获“集智计划”&#xff08;人工智能赛道&#xff09;标杆奖及争先奖。 实景三维是我国的数字基础设施&…

【Go】protobuf介绍及安装

目录 一、Protobuf介绍 1.Protobuf用来做什么 2. Protobuf的序列化与反序列化 3. Protobuf的优点和缺点 4. RPC介绍 <1>文档规范 <2>消息编码 <3>传输协议 <4>传输性能 <5>传输形式 <6>浏览器的支持度 <7>消息的可读性和…

R语言实验三

1、读取一个文件并进行如下操作。 ①使用命令清空工作空间&#xff0c;使用read.table读取exam_1.txt文件&#xff0c;将文件保存到data变量中&#xff0c;数据第一行设置为列名&#xff0c;第一列是行名。 ②判断对象data是否为矩阵。 ③将对象转换为矩阵&#xff0c;记为d…

【SpringBoot3+Vue3】七【后续2】【番外篇】- (使用docke部署)

目录 一、maven打包后端服务 1、clean 2、package 3、查看jar包 二、部署java后端服务 1、使用dockerfile构建一个java17的镜像 1.1 使用dokcerfile构建容器命令 1.2 方式一 将jar打包进容器镜像 1.3 方式二 jar不打包进容器镜像&#xff0c;通过映射主机目录映射方式…

mysql 查询提取json 并去除双引号

1.建表语句 CREATE TABLE uset_test_demo (id bigint(20) NOT NULL AUTO_INCREMENT,context text,PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT4 DEFAULT CHARSETutf8;2.源数据 {"title": "Harry Potter","author": "J.K. Rowling&qu…

Linux基础项目开发1:量产工具——文字系统(四)

前言&#xff1a; 前面我们已经把显示系统&#xff0c;输入系统的框架搭建好了&#xff0c;那么有了输入和显示&#xff0c;显示的内容应该是什么呢&#xff1f;这节就要让我们一起对显示的内容&#xff0c;文字系统进行搭建。 目录 一、数据结构抽象 1.描述一个文字的位图&a…

ubuntu系统下搭建本地物联网mqtt服务器的步骤

那么假如我们需要做一些终端设备&#xff0c;例如温湿度传感器、光照等物联网采集设备要接入呢&#xff1f;怎么样才能将数据报送到服务器呢&#xff1f; 以下内容基于我们ubuntu系统下的emqx成功启动的基础上。我们可以用浏览器键入控制板的地址&#xff0c;如果启动成功&…

特征相关性计较

Pearson相关系数 用于度量两个连续型变量之间的线性关系。取值范围在-1到1之间&#xff0c;0表示无线性关系&#xff0c;1表示完全正相关&#xff0c;-1表示完全负相关 import pandas as pd# 创建一个包含两个连续型变量的DataFrame data {Variable1: [1, 2, 3, 4, 5],Vari…

iOS简单理解区分MVC、MVP、MVVM

MVC、MVP、MVVM 前言 这篇文章简单介绍MVC、MVP和MVVM三种架构&#xff0c;并配上一个简单的Swift demo来区分MVC和MVVM两种架构。 MVC 传统MVC 下图是传统结构MVC&#xff0c;可以看到这种结构是紧耦合的&#xff0c;不推荐使用。 苹果的MVC 如下图&#xff0c;这是苹果…

AI产业前瞻报告:探讨GPTs背后的产业逻辑:拉开AIGC应用生态的帷幕

今天分享的是AI系列深度研究报告&#xff1a;《AI产业前瞻报告&#xff1a;探讨GPTs背后的产业逻辑&#xff1a;拉开AIGC应用生态的帷幕》。 &#xff08;报告出品方&#xff1a;光大证券&#xff09; 报告共计&#xff1a;13页 1、GPTs 拉开 AIGC 应用生态的帷幕 1.1、 Ope…

系列二十二、各种注解

一、Import # 用法 1&#xff09;Import(User.class)&#xff1a;如果导入的是配置类&#xff0c;将会按照配置类正常解析&#xff0c;如果是个普通类就会解析成bean 2&#xff09;Import&#xff08;实现了ImportSelector接口的类.class&#xff09;&#xff1a;可以一次性注册…

Python爬虫基础之Scrapy框架详解

目录 1. 简介2. Scrapy的安装3. Scrapy的架构4. Scrapy的数据流程5. Scrapy开发流程5.1 创建项目5.2 创建Spider5.3 创建Item5.4 编写Spider5.5 运行Spider 参考文献 原文地址&#xff1a;https://program-park.top/2023/12/01/reptile_5/ 本文章中所有内容仅供学习交流使用&am…

0Ω电阻最大过流能力及作用用途

0Ω电阻最大过流能力及作用用途 0Ω电阻过流能力0Ω电阻的作用 0Ω电阻过流能力 0Ω电阻不一定是真正的0Ω电阻&#xff0c;0Ω电阻存在一定的阻值偏差&#xff0c;主要看生产电阻厂商做哪种了。厂商都是根据电阻标准文件 EN60115-2&#xff0c; 里头0Ω电阻实际最大阻值有 10…

JAVA全栈开发 day15_集合(Set接口、增强For循环、Map体系)

一、增加for遍历集合 语法&#xff1a; for(数据类型 变量名: 数组名或集合){​ }//集合遍历 &#xff0c;推荐使用增加for 1.静态导入 注意事项&#xff1a; 方法必须是静态注意不要和本类的方法同名&#xff0c;如果同名&#xff0c;记得加前缀&#xff0c;由此可…

Git——分支应用进阶

主要内容包括以下几个方面&#xff1a; 长期分支和短期分支的类型以及用途。多种分支模型&#xff0c;其中包括基于工作流的主题分支。不同分支模型的发布流程。在多个预览版程序中使用分支修复安全问题。远程跟踪分支和refspecs规范&#xff0c;以及默认远程版本库配置。拉取…

Mongodb 开启oplog,java监听oplog并写入关系型数据库

开启Oplog windows mongodb bin目录下找到配置文件/bin/mongod.cfg,配置如下&#xff1a; replication:replSetName: localoplogSizeMB: 1024双击mongo.exe 执行 rs.initiate({_id: "local", members: [{_id: 0, host: "localhost:27017"}]})若出现如…

深入理解前端路由:构建现代 Web 应用的基石(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

多线程(初阶六:单例模式)

一、单例模式的简单介绍 二、饿汉模式 三、懒汉模式 四、饿汉模式和懒汉模式的线程安全问题分析 一、单例模式的简单介绍 单例模式是一种设计模式&#xff0c;其中设计模式是软性的规定&#xff0c;与它关联的框架是硬性的规定&#xff0c;这些都是大佬已经设计好了的&…