【C++】设计模式

目录

设计模式概述

单例模式

饿汉模式

懒汉模式

工厂模式

简单工厂模式

工厂方法模式

抽象工厂模式

观察者模式


设计模式概述

设计模式:一套反复被人使用、多数人知晓的、经过分类编目的代码设计经验的总结。一种固定的写代码的思维逻辑方式,一种设计类与类之间关系的抽象思维的定式。

设计模式的目的是应付客观情况的变化,提高代码的复用性和维护性。

设计模式的分类

  • 创建型模式(设计对象实例化的方式,5种):单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式
  • 结构型模式(描述如何组合类和对象获得更大的结构,7种):代理模式、装饰者模式、适配器模式、桥接模式、组合模式、外观模式、享元模式
  • 行为型模式(描述类和对象的交互以及分配职责,11种):模板方法模式、命令模式、责任链模式、策略模式、中介者模式、观察者模式、备忘录模式、访问者模式、状态模式、解释器模式、迭代器模式

设计模式的七大设计原则

  • 单一职责原则:一个类应该只有一个引起它变化的原因,变化的方向隐含它的职责
  • 开放封闭原则:对扩展开放,对更改封闭,类模块可扩展但不可修改
  • 依赖倒置原则:高层(稳定)不依赖底层(变化),两者依赖抽象(稳定),抽象(稳定)不依赖细节(变化),细节依赖抽象(稳定)
  • 里氏替换原则:子类必须能够替代他们的基类
  • 接口隔离原则:一个接口只提供一种对外功能,接口应该小而完备,尽量私有化用户用不到的接口
  • 优先组合而非继承原则:类的继承通常是“白箱复用”,类的组合通常是“黑箱复用”,继承在一定程序上破坏封装性,子类和父类的耦合度高
  • 迪米特法则:对象应该对其他对象尽可能少的了解,各个模块相互调用时,提供一个统一的接口来实现

在实际设计模式选择中,并不是所有的设计原则都要满足,而是根据不同的应用场景尽可能多的满足设计原则。

单例模式

单例模式:在程序的生命周期内,一个类只能有一个实例,确保该类的唯一性。

单例模式分为饿汉模式懒汉模式,区别在于创建实例的时间不同。

  • 饿汉模式:系统运行时,在主程序之前就直接初始化创建实例,当需要时直接调用实例。饿汉模式不存在多线程的线程安全问题,但缺陷是若初始化数据过多会导致程序启动慢、多个单例创建并有依赖关系时无法控制。
  • 懒汉模式:系统运行时,实例并不创建,只有当第一次需要使用这个实例的时候,才会初始化创建实例,这种方式需要考虑线程安全。

饿汉模式

#include <iostream>
#include <map>
using namespace std;

class Singleton
{
public:
	static Singleton& get_instance()
	{
		return _st;
	}

	void insert(string name, int salary)
	{
		_info[name] = salary;
	}

	void print()
	{
		for (auto& e : _info)
		{
			cout << e.first << " : " << e.second << endl;
		}
		cout << endl;
	}

private:
	Singleton()
	{}

	Singleton(const Singleton& st) = delete;
	Singleton& operator=(const Singleton& st) = delete;

private:
	map<string, int> _info;
	static Singleton _st;
};

Singleton Singleton::_st;

int main()
{
	Singleton::get_instance().insert("张三", 12000);
	Singleton& st1 = Singleton::get_instance();
	st1.insert("李四", 30000);
	st1.insert("王五", 45000);
	st1.insert("赵六", 60000);

	st1.print();

	Singleton& st2 = Singleton::get_instance();
	st2.print();
	st2.insert("周七", 8000);
	st2.insert("张三", 24000);

	st1.print();
	st2.print();
	// st1、st2 表示同一个实例

	return 0;
}

懒汉模式

第一种方式:加锁保证线程安全

#include <iostream>
#include <map>
#include <mutex>
using namespace std;

// RAII锁管理类
template<class Lock>
class LockGuard
{
public:
	LockGuard(Lock& lk)
		: _lk(lk)
	{
		_lk.lock();
	}

	~LockGuard()
	{
		_lk.unlock();
	}

private:
	Lock& _lk;
};

class Singleton
{
public:
	static Singleton& get_instance()
	{
		// 双重验证
		if (_pst == nullptr)		// 判断是否需要加锁,提高效率
		{
			LockGuard<mutex> lock(_mtx);
			//lock_guard<mutex> lock(_mtx);	// 锁管理器可以直接使用库里面的
			if (_pst == nullptr)	// 判断是否已经创建实例,保证线程安全
			{
				_pst = new Singleton;
			}
		}

		return *_pst;
	}

	void insert(string name, int salary)
	{
		_info[name] = salary;
	}

	void print()
	{
		for (auto& e : _info)
		{
			cout << e.first << " : " << e.second << endl;
		}
		cout << endl;
	}

	// 单例模式一般不考虑资源回收问题,都是在程序结束时自动回收资源
	// 只有在需要在需要手动回收做数据处理的时候,再提供回收接口
	void del_instance()
	{
		lock_guard<mutex> lock(_mtx);
		if (_pst)
		{
			delete _pst;
			_pst = nullptr;
		}
	}

private:
	Singleton()
	{}

	Singleton(const Singleton& st) = delete;
	Singleton& operator=(const Singleton& st) = delete;

private:
	map<string, int> _info;
	static Singleton* _pst;
	static mutex _mtx;
};

Singleton* Singleton::_pst;
mutex Singleton::_mtx;

int main()
{
	Singleton::get_instance().insert("张三", 12000);
	Singleton& st1 = Singleton::get_instance();
	st1.insert("李四", 30000);
	st1.insert("王五", 45000);
	st1.insert("赵六", 60000);

	st1.print();

	Singleton& st2 = Singleton::get_instance();
	st2.print();
	st2.insert("周七", 8000);
	st2.insert("张三", 24000);

	st1.print();
	st2.print();

	return 0;
}

第二种方式:静态局部对象保证线程安全

#include <iostream>
#include <map>
#include <mutex>
using namespace std;

class Singleton
{
public:
	static Singleton& get_instance()
	{
		static Singleton st;
		return st;
	}

	void insert(string name, int salary)
	{
		_info[name] = salary;
	}

	void print()
	{
		for (auto& e : _info)
		{
			cout << e.first << " : " << e.second << endl;
		}
		cout << endl;
	}

private:
	Singleton()
	{}

	Singleton(const Singleton& st) = delete;
	Singleton& operator=(const Singleton& st) = delete;

private:
	map<string, int> _info;
};

int main()
{
	Singleton::get_instance().insert("张三", 12000);
	Singleton& st1 = Singleton::get_instance();
	st1.insert("李四", 30000);
	st1.insert("王五", 45000);
	st1.insert("赵六", 60000);

	st1.print();

	Singleton& st2 = Singleton::get_instance();
	st2.print();
	st2.insert("周七", 8000);
	st2.insert("张三", 24000);

	st1.print();
	st2.print();

	return 0;
}

C++11之前,静态局部变量的初始化不能保证线程安全,C++11之后,静态局部变量的初始化是线程安全的。

工厂模式

简单工厂模式

简单工厂模式属于类的创建型模式,又叫做静态工厂模式。通过专门定义一个类来负责创建其他类的示例,被创建的示例通常都具有共同的父类。

实现步骤:

  1. 提供一个工厂类:负责创建所有实例的内部逻辑,可被外界直接调用,创建所需的产品对象。
  2. 提供一个抽象产品类:简单工厂模式所创建的所有模式的父类,它负责描述所有实例所共有的公共接口。
  3. 提供多个具体产品类:简单工厂模式所创建的具体实例对象。

简单工厂类代码示例:实现运算器

#include <iostream>
using namespace std;

// 抽象产品类
class Operation
{
public:
	double _lVal;
	double _rVal;
	virtual double get_result() = 0;
};

// 加减乘除具体产品类
class AddOperator : public Operation
{
	double get_result()
	{
		return _lVal + _rVal;
	}
};

class SubOperator : public Operation
{
	double get_result()
	{
		return _lVal - _rVal;
	}
};

class MulOperator : public Operation
{
	double get_result()
	{
		return _lVal * _rVal;
	}
};

class DivOperator : public Operation
{
	double get_result()
	{
		return _lVal / _rVal;
	}
};

// 工厂类
class OperatorFactory
{
public:
	static Operation* create_operation(const char op)
	{
		switch (op)
		{
		case '+':
			return new AddOperator();
		case '-':
			return new SubOperator();
		case '*':
			return new MulOperator();
		case '/':
			return new DivOperator();
		default:
			return nullptr;
		}
	}
};

int main()
{
	Operation* add = OperatorFactory::create_operation('+');
	add->_lVal = 10;
	add->_rVal = 20;
	cout << add->get_result() << endl;

	add = OperatorFactory::create_operation('-');
	add->_lVal = 10;
	add->_rVal = 20;
	cout << add->get_result() << endl;

	return 0;
}

优点:

  • 帮助封装,实现组件封装,面向接口编程
  • 解耦合,客户端和具体实现类的解耦合

缺点:

  • 可能增加客户端的复杂度
  • 不方便扩展

工厂方法模式

工厂方法模式又被称为多态工厂模式。工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新产品。

工行方法模式和简单工厂模式在结构上相似。工厂方法类的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上,工厂方法类之所以又叫多态工厂类是因为具体工厂类都有共同的接口,或者有共同的抽象父类。当系统拓展需要添加新的产品对象时,仅仅需要添加一个具体对象和一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了“开放-封闭”原则,而简单工厂模式在添加新产品对象后不得不修改工厂方法,拓展性不好。

实现步骤:

  1. 提供一个抽象工厂类:所有具体工厂类的父类
  2. 提供与产品对应的工厂类:负责实例化产品对象
  3. 提供一个抽象产品类:所有产品的父类
  4. 提供一个或多个产品类:工厂方法模式所创建的具体实例对象

 工厂方法模式代码示例:建造飞机火箭

#include <iostream>
using namespace std;

// 抽象产品类
class AbstractProduct
{
public:
	virtual void make_product() = 0;

	virtual ~AbstractProduct()
	{}
};

// 抽象工厂类
class AbstractFactory
{
public:
	virtual AbstractProduct* create_product() = 0;

	virtual ~AbstractFactory()
	{}
};

// 具体产品类
class PlaneProduct : public AbstractProduct
{
public:
	void make_product()
	{
		cout << "make a plane..." << endl;
	}
};

class PlaneFactory : public AbstractFactory
{
	AbstractProduct* create_product()
	{
		return new PlaneProduct;
	}
};

class RocketProduct : public AbstractProduct
{
public:
	void make_product()
	{
		cout << "make a rocket..." << endl;
	}
};

class RocketFactory :public AbstractFactory
{
	AbstractProduct* create_product()
	{
		return new RocketProduct;
	}
};

int main()
{
	AbstractFactory* factory = new PlaneFactory;
	AbstractProduct* product = factory->create_product();
	product->make_product();

	factory = new RocketFactory();
	product = factory->create_product();
	product->make_product();

	return 0;
}

优点:

  • 需求改变时改动小
  • 具体的创建示例过程与客户端分离

缺点:

  • 新增产品时,工程量大

抽象工厂模式

抽象工厂模式是所有形态的工厂模式中最为抽象和一般性的,抽象工厂模式可以向客户端提供一个接口,使得客户端不必指定产品的具体类型的情况下,能够创建多个产品族的产品对象。

抽象工厂方法是针对一个产品族,使得易于交换产品系列,只需改变具体的工厂就可以使用不同的产品配置。当一个族中的产品对象被设计成一起工作且一个应用只是用同一族的对象,例如设计系统生成不同的UI界,按钮、边框等UI元素在一起使用,并且只能同属于一种风格,这很容易使用抽象工厂实现。

实现步骤:

  1. 提供一个抽象工厂类:声明一组创建一族产品的方法
  2. 提供一个具体工厂类:实现在抽象工厂创建产品的工厂方法
  3. 提供一个抽象产品类:抽象产品中声明了产品具有的业务方法
  4. 提供一个具体产品类:实现抽象产品接口中声明的业务方法

抽象工厂代码示例:鼠标键盘产品族

#include <iostream>
using namespace std;

// 抽象产品
class Product
{
public:
	virtual void show() = 0;

	virtual ~Product() {}
};

// 抽象产品族1:键盘
class Keyboard : public Product 
{
public:
	virtual ~Keyboard() {}
};

class LogiKeyboard : public Keyboard
{
	void show()
	{
		cout << "罗技键盘" << endl;
	}
};

class RazerKeyboard : public Keyboard
{
	void show()
	{
		cout << "雷蛇键盘" << endl;
	}
};

// 抽象产品族2:鼠标
class Mouse : public Product
{
public:
	virtual ~Mouse() {}
};

class LogiMouse : public Mouse
{
	void show()
	{
		cout << "罗技鼠标" << endl;
	}
};

class RazerMouse : public Mouse
{
	void show()
	{
		cout << "雷蛇鼠标" << endl;
	}
};

// 抽象工厂
class AbstractFactory
{
public:
	virtual Keyboard* create_keyboard() = 0;
	virtual Mouse* create_mouse() = 0;

	virtual ~AbstractFactory() {}
};

// 具体工程
class LogiFactory : public AbstractFactory
{
	Keyboard* create_keyboard()
	{
		return new LogiKeyboard;
	}

	Mouse* create_mouse()
	{
		return new LogiMouse;
	}
};

class RazerFactory : public AbstractFactory
{
	Keyboard* create_keyboard()
	{
		return new RazerKeyboard;
	}

	Mouse* create_mouse()
	{
		return new RazerMouse;
	}
};

int main()
{
	AbstractFactory* factory = new LogiFactory;
	Keyboard* keyboard = factory->create_keyboard();
	Mouse* mouse = factory->create_mouse();

	keyboard->show();
	mouse->show();

	delete keyboard;
	delete mouse;
	delete factory;

	factory = new RazerFactory;
	keyboard = factory->create_keyboard();
	mouse = factory->create_mouse();

	keyboard->show();
	mouse->show();

	delete keyboard;
	delete mouse;
	delete factory;
	keyboard = nullptr;
	mouse = nullptr;
	factory = nullptr;

	return 0;
}

优点:

  • 抽象工厂封装了变化,封装了对象创建的具体细节
  • 增加新的产品族很方便,无须修改已有系统
  • 针对接口进行编程,而不是针对具体产品进行编程

缺点:

  • 增加新的产品等级结构需对原系统做较大修改(违背“开放-封闭原则”)

观察者模式

观察者模式定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖都会收到通知并自动更新。

实现步骤:

  1. 抽象主题(抽象被观察者)角色:把所有观察者角色保存在一个集合里,每个主题都有任意数量的观察者。抽象主题提供一个接口,可以增加和删除对象。
  2. 具体主题(具体被观察者)角色:将所有状态存入具体观察者对象。在具体主题的内部发生改变时,给所有注册过的观察者发送通知。
  3. 抽象观察者角色:观察者的抽象类。定义了一个更新接口,使得在得到主题改通知时更新自己。
  4. 具体观察者角色:实现抽象观察者定义的接口。在得到主题更改通知时更新自身状态。

示例:气象系统有三个部分分别是气象站(获取实际气象数据的物理装置)、WeatherData对象(用来追踪气象站的数据并更新布告板)、布告板(显示当前天气状态给用户)。WeatherData对象知道如何跟物理气象站联系,以取得更新信息。WeatherData对象会随即更新三个布告板的显示:目前状况(温度、湿度、气压)、气象统计、天气预报。我们的程序是建立一个应用,利用WeatherData对象取得数据,并更新三个布告板:目前状况、气象统计和天气预报。

#include <iostream>
#include <list>
using namespace std;

class Observer
{
public:
	virtual void update(float tempreature, float humudity, float pressure) = 0;

	virtual ~Observer()
	{}
};

class DisplayElement
{
public:
	virtual void display()
	{};

	virtual ~DisplayElement()
	{}
};

class Subject
{
public:
	virtual void regsiter_observer(Observer* obs)
	{};

	virtual void remove_observer(Observer* obs)
	{};

	virtual void notify_observer() = 0;

	virtual ~Subject()
	{}
};

// WeatherData类:注册、删除、通知观察者
class WeatherData : public Subject
{
public:
	void regsiter_observer(Observer* obs)
	{
		_observers.push_back(obs);
	}

	void remove_observer(Observer* obs)
	{
		_observers.remove(obs);
	}

	void notify_observer()
	{
		list<Observer*>::iterator it = _observers.begin();
		while (it != _observers.end())
		{
			Observer* obs = *it;
			obs->update(_tempreature, _humidity, _pressure);
			++it;
		}
	}

	void measurements_changed()
	{
		notify_observer();
	}

	void set_measurements(float t, float h, float p)
	{
		_tempreature = t;
		_humidity = h;
		_pressure = p;
		measurements_changed();
	}

private:
	list<Observer*> _observers;
	float _tempreature;
	float _humidity;
	float _pressure;
};

// 布告板:申请注册、实时更新和显示
class CurrentConditionsDisplay : public Observer, public DisplayElement
{
public:
	CurrentConditionsDisplay(WeatherData* weatherData)
	{
		_weatherData = weatherData;
		_weatherData->regsiter_observer(this);
	}

	void update(float tempreature, float humidity, float pressure)
	{
		_tempreature = tempreature;
		_humidity = humidity;
		_pressure = pressure;
		display();
	}

	void display()
	{
		cout << "Current Conditions" << endl;
		cout << "tempreature: " << _tempreature << endl;
		cout << "humidity: " << _humidity << endl;
		cout << "pressure: " << _pressure << endl;
		cout << endl;
	}

private:
	float _tempreature;
	float _humidity;
	float _pressure;
	Subject* _weatherData;
};

// 客户代码
int main()
{
	WeatherData* testData = new WeatherData();
	CurrentConditionsDisplay* testDisplay = new CurrentConditionsDisplay(testData);

	testData->set_measurements(32.5, 65, 30.4);
	testData->set_measurements(37.5, 75, 34.4);
	testData->set_measurements(22.5, 45, 26.4);
	// 修改数据,实现自动更新布告板

	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

小学妹刚毕业没地方住想来借宿,于是我连夜用Python给她找了个好房子,我真是太机智了

事情是这样的&#xff0c;小学妹刚毕业参加工作&#xff0c;人生地不熟的&#xff0c;因为就在我附近上班&#xff0c;所以想找我借宿。。。 想什么呢&#xff0c;都不给住宿费&#xff0c;想免费住&#xff1f;于是我用Python连夜给她找了个单间&#xff0c;自己去住吧&#…

ChatGPT api 接口调用测试

参考文档&#xff1a; https://platform.openai.com/docs/quickstart/build-your-application示例说明&#xff1a; 本示例会生成一个简单的ChatGPT api接口调用server程序&#xff0c;该程序可以给用户输入的宠物类别为宠物取三个名字。打开网页后&#xff0c;会看到用户输入…

机器学习在生态、环境经济学中的应用及论文写作

近年来&#xff0c;人工智能领域已经取得突破性进展&#xff0c;对经济社会各个领域都产生了重大影响&#xff0c;结合了统计学、数据科学和计算机科学的机器学习是人工智能的主流方向之一&#xff0c;目前也在飞快的融入计量经济学研究。表面上机器学习通常使用大数据&#xf…

【一起撸个深度学习框架】6 折与曲的相会——激活函数

CSDN个人主页&#xff1a;清风莫追欢迎关注本专栏&#xff1a;《一起撸个DL框架》GitHub获取源码&#xff1a;https://github.com/flying-forever/OurDLblibli视频合集&#xff1a;https://space.bilibili.com/3493285974772098/channel/series 文章目录 6 折与曲的相会——激活…

使用Visual Studio进行cuda编程配置环境四大坑(附解决方案)

写在前面&#xff0c;用于没有使用过Visual Studio进行cuda编程的同学看&#xff0c;以免在安装环境的时候踩到坑 第一坑&#xff1a;CUDA版本与NVIDIA显卡版本不匹配问题: 安装cuda版本坑&#xff0c;强烈建议看下自己的显卡支持什么版本的cuda&#xff0c;切记不要用最新版…

IP 子网划分详解

文章目录 1 概述1.1 划分目的1.2 划分原则1.3 子网掩码 2 IP 子网划分示例3 网工软考真题3.1 判断网络号和主机号3.2 计算可容纳的主机数 1 概述 IP 子网划分&#xff1a;实际上就是设计 子网掩码 的过程。原因&#xff1a;由于在五类的IP地址中&#xff0c;网络号与主机号的的…

Class 02 - R语言Rstudio的安装

Class 02 - R语言&Rstudio的安装 下载和安装R安装前准备下载R语言安装R语言开始使用R语言 下载和安装RStudio安装前准备下载RStudio安装RStudio开始使用RStudio如何编写代码 下载和安装R 在这个部分中&#xff0c;你将完成在计算机上下载和安装R语言程序。当安装完成后&am…

ThingsBoard部署tb-gateway并配置OPCUA

1、安装 我实在自己的虚拟机上安装,使用官方Docker的安装方式 docker run -it -v ~/.tb-gateway/logs:/thingsboard_gateway/logs -v ~/.tb-gateway/extensions:/thingsboard_gateway/extensions -v ~/.tb-gateway/config:/thingsboard_gateway/config --name tb-gateway --…

JavaScript的三座大山

前言&#xff1a;这个题目是抄的&#xff0c;看着很有意思&#xff0c;就拿过用了&#xff0c;毕竟CV是程序员的基本功底嘛&#xff0c;顺带把图也拿过来了 作用域和闭包 这个几乎是天天在用的东西&#xff0c;可能有些人甚至不知道这个概念&#xff0c;但是用到过这种方法去解…

Html中使用jquery通过Ajax请求WebService接口以及跨域问题解决

场景 VS2019新建WebService/Web服务/asmx并通过IIS实现发布和调用&#xff1a; VS2019新建WebService/Web服务/asmx并通过IIS实现发布和调用_霸道流氓气质的博客-CSDN博客 在上面实现发布WebService的基础上&#xff0c;怎样在html中通过jquery对接口发起 请求和解析数据。…

测试4年,跳槽一次涨8k,我跳了3次···

最近有人说&#xff0c;现在测试岗位初始工资太低了&#xff0c;有些刚刚入行的程序员朋友说自己工资连5位数都没有.....干了好几年也没怎么涨。看看别人动辄月薪2-3万&#xff0c;其实我想说也没那么难。说下如何高效地拿到3w。 1.暂且把刚入行的条件设低些吧&#xff0c;大专…

【野火启明_瑞萨RA6M5】梦的开始 ---- 点灯(FSP库)

文章目录 一、FSP配置二、hal_entry入口函数三、封装 LED 设备驱动程序下载验证 一、FSP配置 对于 Keil 开发环境&#xff1a; 拷贝一份之前的 Keil 工程模板 “06_Template”&#xff0c; 然后将工程文件夹重命名为 “11_GPIO_LED”&#xff0c;并进入该文件夹里面双击 Keil …

EW代理工具的使用说明

一、EW介绍 Earthworm&#xff08;EW&#xff09; 是一套便携式的网络穿透工具&#xff0c;具有 SOCKS v5服务架设和端口转发两大核心功能&#xff0c;可在复杂网络环境下完成网络穿透。 该工具能够以“正向”、“反向”、“多级级联”等方式打通一条网络隧道&#xff0c;直达…

5年自动化测试,终于进字节跳动了,年薪30w其实也并非触不可及

一些碎碎念 什么都做了&#xff0c;和什么都没做其实是一样的&#xff0c;走出“瞎忙活”的安乐窝&#xff0c;才是避开弯路的最佳路径。希望我的经历能帮助到有需要的朋友。 在测试行业已经混了5个年头了&#xff0c;以前经常听到开发对我说&#xff0c;天天的点点点有意思没…

vue3的学习【超详细】

目录 一、vue3的优点1、vue3的优点 二、常用的API1、setup&#xff08;Composition API&#xff09;2、生命周期&#xff08;Composition API&#xff09;3、ref函数和reactive函数用法和区别&#xff08;Composition API&#xff09;1、ref2、reactive3、ref和reactive的区别 …

【JAVA】this关键字和static关键字

目录 1.this关键字 2.static关键字 容易混淆的问题 1.this关键字 一个对象一个this。this是一个变量&#xff0c;是一个关键字&#xff0c;是一个引用。this保存当前对象的内存地址&#xff0c;指向自身。所以&#xff0c;严格意义上来说&#xff0c;this代表的就是“当前对象…

顶象助力如祺出行打造高品质服务

近日&#xff0c;广东省自然资源厅审批通过了如祺出行提交的测绘资质申请&#xff0c;如祺出行获得地理信息系统工程和互联网地图服务两个专业的乙级测绘资质。此次获批意味着&#xff0c;如祺出行能够在许可区域内依法合规开展数据标注和场景仿真等相关业务&#xff0c;构建全…

【Spring框架全系列】第一个Spring程序

&#x1f3d9;哈喽&#xff0c;大家好&#xff0c;我是小浪。那么从今天开始&#xff0c;我就要开始更新spring框架全系列的博客了&#xff1b;本专栏免费阅读&#xff0c;最好能够点个订阅&#xff0c;以便于后续及时收到更新信息哈&#xff01;&#x1f3df; &#x1f4f2;目…

全网最详细,性能测试各种测试场景分析+性能测试基准测(超细总结)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 面对日益复杂的业…

生成一个手绘图为底图的导游图

目录 1 前言 2 新增一个景区 3 生成验证码用于上传手绘图切片 4 免费下载切图客户端并配置、切图 5 增加景点 1 前言 上一篇演示了制作一个简版导游图。简版导游图的优点是制作简单、快速&#xff0c;不需要第三方软件&#xff0c;缺点是略显简陋、不够专业。 本编介绍制…