常用设计模式总结

2023-11-18

设计模式的相关知识,很多书籍和博客中都有详细总结,本文总结的目的:
1、将自己学习到的设计模式的知识按照自己的逻辑重新总结,方便查看和记忆。
2、方便让自己对设计模式中常用的知识有一个系统的认知。

设计模式

《⼤话设计模式》⼀书中提到 24 种设计模式,这 24 种设计模式没必要⾯⾯俱到,但⼀定要深⼊了解其中的⼏种,最好结合⾃⼰在实际开发过程中的例⼦进⾏深⼊的了解。

设计模式分类

设计模式分为三类:

  • 创造型模式:单例模式、⼯⼚模式、建造者模式、原型模式

  • 结构型模式:适配器模式、桥接模式、外观模式、组合模式、装饰模式、享元模式、代理模式

  • ⾏为型模式:责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、 观察者模式、状态模式、策略模式、模板⽅法模式、访问者模式。

几种常见的设计模式

  • 单例模式:保证⼀个类仅有⼀个实例,并提供⼀个访问它的全局访问点。

  • ⼯⼚模式:包括简单⼯⼚模式、抽象⼯⼚模式、⼯⼚⽅法模式

    • 简单⼯⼚模式:主要⽤于创建对象。⽤⼀个⼯⼚来根据输⼊的条件产⽣不同的类,然后根据不同类的虚函数得到不同的结果。

    • 抽象⼯⼚模式:定义了⼀个创建⼀系列相关或相互依赖的接⼝,⽽⽆需指定他们的具体类。

  • 观察者模式:定义了⼀种⼀对多的关系,让多个观察对象同时监听⼀个主题对象,主题对象发⽣变化时,会通知所有的观察者,使他们能够更新⾃⼰。

  • 装饰模式:动态地给⼀个对象添加⼀些额外的职责,就增加功能来说,装饰模式⽐⽣成派⽣类更为灵活。

单例模式

单例模式的适用场景

  • 系统只需要⼀个实例对象,或者考虑到资源消耗的太⼤⽽只允许创建⼀个对象。
  • 客户调⽤类的单个实例只允许使⽤⼀个公共访问点,除了该访问点之外不允许通过其它⽅式访问该实例(就是共有的静态⽅法)。

所以单例模式一般用在对实例数量有严格要求的地方,比如数据池,线程池,缓存,session回话等等。

构成的条件:

  • 私有化它的构造函数,以防止外界创建单例类的对象;
  • 使用类的私有静态指针变量指向类的唯一实例;
  • 使用一个公有的静态方法获取该实例。

单例模式有两种:饿汉模式和懒汉模式

《C++ 单例模式》https://zhuanlan.zhihu.com/p/37469260

《析构函数声明为私有的作用》https://blog.csdn.net/jia_xiaoxin/article/details/3348045

饿汉模式

饿汉模式(线程安全):顾名思义,饿了就饥不择⻝了,所以在单例类定义的时候就进行实例化。

在最开始的时候静态对象就已经创建完成,设计方法是类中包含⼀个静态成员指针,该指针指向该类的⼀个对象,提供⼀个公有的静态成员方法,返回该对象指针,为了使得对象唯⼀,构造函数设为私有。由于在main函数之前初始化,所以没有线程安全的问题。

#include <iostream>
#include <algorithm>
using namespace std;
class SingleInstance {
public:
    // 用户通过接口获取实例:使用 static 类成员函数
	static SingleInstance* GetInstance() {
		return &ins;
	}	
private:
    static SingleInstance ins;  // 注意此处不是指针
private:
	//涉及到创建对象的函数都设置为private
    SingleInstance(){}
	SingleInstance() { std::cout<<"SingleInstance() 饿汉"<<std::endl; }
	SingleInstance(const SingleInstance& other) {};
	SingleInstance& operator=(const SingleInstance& other) {return *this; }
    ~SingleInstance(){};
};
SingleInstance SingleInstance::ins;  // 静态成员函数定义并初始化

int main() {
	//因为不能创建对象所以通过静态成员函数的⽅法返回静态成员变量
	SingleInstance* ins = SingleInstance::GetInstance();
	return 0; 
}
//输出 SingleInstance() 饿汉
懒汉模式

懒汉(线程安全需要加锁):顾名思义,不到万不得已就不会去实例化类,也就是在第⼀次⽤到的类实例的时候才会去实例化。尽可能的晚的创建这个对象的实例,即在单例类第⼀次被引⽤的时候就将自己初始化,C++ 很多地方都有类型的思想,比如写时拷贝,晚绑定等。

原始版

class SingleInstance
{
private:
	static SingleInstance* instance;  // 与饿汉模式相比,此处是指针
private:
	SingleInstance() {};
	~SingleInstance() {};
	SingleInstance(const SingleInstance&);
	SingleInstance& operator=(const SingleInstance&);
public:
	static SingleInstance* getInstance() 
        {
		if(instance == NULL) 
			instance = new SingleInstance();
		return instance;
	}
};

// init static member
SingleInstance* SingleInstance::instance = NULL;

这种原始的方法存在内存泄露的问题,有两种解决方法:

  1. 使用智能指针
  2. 使用静态的嵌套类对象

对于第二种解决方法,代码如下:

class SingleInstance
{
private:
	static SingleInstance* instance;
private:
	SingleInstance() { };
	~SingleInstance() { };
	SingleInstance(const SingleInstance&);
	SingleInstance& operator=(const SingleInstance&);
private:
	class Deletor {
	public:
		~Deletor() {
			if(SingleInstance::instance != NULL)
				delete SingleInstance::instance;
		}
	};
	static Deletor deletor;
public:
	static SingleInstance* getInstance() {
		if(instance == NULL) {
			instance = new SingleInstance();
		}
		return instance;
	}
};
// init static member
SingleInstance* SingleInstance::instance = NULL;
SingleInstance::Deletor  SingleInstance::deletor;

在程序运行结束时,系统会调用静态成员deletor的析构函数,该析构函数会删除单例的唯一实例。使用这种方法释放单例对象有以下特征:

  • 在单例类内部定义专有的嵌套类。
  • 在单例类内定义私有的专门用于释放的静态成员。
  • 利用程序在结束时析构全局变量的特性,选择最终的释放时机。

这个代码在单线程环境下是正确无误的,但是当拿到多线程环境下时这份代码就会出现race condition, 要使其线程安全,能在多线程环境下实现单例模式,我们首先想到的是利用同步机制来正确的保护我们的shared data。

#include <pthread.h>
#include <iostream>
#include <algorithm>
using namespace std;
class SingleInstance {
public:
	static SingleInstance* GetInstance() {
		if (ins == nullptr) {
			pthread_mutex_lock(&mutex);
			if (ins == nullptr) {
				ins = new SingleInstance();
			}
			pthread_mutex_unlock(&mutex);
		}
		return ins;
	}
	~SingleInstance(){};
	//互斥锁
	static pthread_mutex_t mutex;
private:
	//涉及到创建对象的函数都设置为private
	SingleInstance() { std::cout<<"SingleInstance() 懒汉"<<std::endl; }
	SingleInstance(const SingleInstance& other) {};
	SingleInstance& operator=(const SingleInstance& other) { return *this; }
	//静态成员
	static SingleInstance* ins;
};

//懒汉式 静态变量需要定义
SingleInstance* SingleInstance::ins = nullptr;
pthread_mutex_t SingleInstance::mutex;

int main(){
	//因为不能创建对象所以通过静态成员函数的⽅法返回静态成员变量
	SingleInstance* ins = SingleInstance::GetInstance();
	delete ins;
	return 0; 
}
//输出 SingleInstance() 懒汉

工厂模式

⼀般情况下,工厂模式分为三种更加细分的类型:简单工厂、工厂⽅法和抽象工厂。

简单工厂模式

可以根据实际的参数不同返回不同的实例。同时在简单工厂模式中会定义⼀个类负责创建其他 类的实例,被创建的实例也通常具有共同的⽗类。简单工厂模式的实质是由⼀个工厂根据传⼊的参数,动态决定应该创建哪⼀个产品类(这些产品类继承⾃⼀个⽗类或接接口)的实例。

#include <iostream>
#include <pthread.h>
using namespace std;
//产品类(抽象类,不能实例化)
class Product{
public:
	Product(){};
	virtual void show()=0; //纯虚函数
};

class productA : public Product{
public:
	productA(){};
	void show(){ std::cout << "product A create!" << std::endl; };
	~productA(){};
};

class productB : public Product{
public:
	productB(){};
	void show(){ std::cout << "product B create!" << std::endl; };
	~productB(){};
};

class simpleFactory{ // ⼯⼚类
public:
	simpleFactory(){};
	Product* product(const string str){
		if (str == "productA")
			return new productA();
		if (str == "productB")
			return new productB();
		return NULL;
	};
};

int main(){
	simpleFactory obj; // 创建⼯⼚
	Product* pro; // 创建产品
	pro = obj.product("productA");
	pro->show(); // product A create!
	delete pro;
	pro = obj.product("productB");
	pro->show(); // product B create!
	delete pro;
	return 0; 
}

工厂模式⽬的就是代码解耦,如果我们不采⽤工厂模式,如果要创建产品 A、B,通常做法采⽤⽤ switch…case语句,那么想⼀想后期添加更多的产品进来,我们不是要添加更多的switch…case 吗?这样就很麻烦,⽽且也不符合设计模式中的开放封闭原则

抽象工厂模式

为了进⼀步解耦,在简单工厂的基础上发展出了抽象工厂模式,即连工厂都抽象出来,实现了 进⼀步代码解耦。

#include <iostream>
#include <pthread.h>
using namespace std;
//产品类(抽象类,不能实例化)
class Product{
public:
	Product(){}
	virtual void show()=0; //纯虚函数
};

class Factory{//抽象类
public:
	virtual Product* CreateProduct()=0;//纯虚函数
};

//产品A
class ProductA:public Product{
public:
	ProductA(){}
	void show(){ std::cout<<"product A create!"<<std::endl; };
};

//产品B
class ProductB:public Product{
public:
	ProductB(){}
	void show(){ std::cout<<"product B create!"<<std::endl; };
};

//⼯⼚类A,只⽣产A产品
class FactorA: public Factory{
public:
	Product* CreateProduct(){
		Product* product_ = nullptr;
		product_ = new ProductA();
		return product_;
	}
};

//⼯⼚类B,只⽣产B产品
class FactorB: public Factory{
public:
	Product* CreateProduct(){
		Product* product_ = nullptr;
		product_ = new ProductB();
		return product_;
	}
};

int main(){
	Product* product_ = nullptr;
	auto MyFactoryA = new FactorA();
	product_ = MyFactoryA->CreateProduct();// 调⽤产品A的⼯⼚来⽣产A产品
	product_->show();
	delete product_;
	auto MyFactoryB=new FactorB();
	product_ = MyFactoryB->CreateProduct();// 调⽤产品B的⼯⼚来⽣产B产品
	product_->show();
	delete product_;
	return 0; 
}
//输出
//product A create! product B create!

观察者模式

观察者模式定义⼀种⼀(被观察类)对多(观察类)的关系,让多个观察对象同时监听⼀个 被观察对象,被观察对象状态发⽣变化时,会通知所有的观察对象,使他们能够更新⾃⼰的状态。 观察者模式中存在两种⻆⾊:

  • **观察者:**内部包含被观察者对象,当被观察者对象的状态发⽣变化时,更新⾃⼰的状态。(接收通知更新状态)

  • **被观察者:**内部包含了所有观察者对象,当状态发⽣变化时通知所有的观察者更新⾃⼰的状态。(发送通知)

应⽤场景:

  • 当⼀个对象的改变需要同时改变其他对象,且不知道具体有多少对象有待改变时,应该考虑使⽤观察者模式;

  • ⼀个抽象模型有两个⽅⾯,其中⼀⽅⾯依赖于另⼀⽅⾯,这时可以⽤观察者模式将这两者封装在独⽴的对象中使它们各⾃独⽴地改变和复⽤。

#include <iostream>
#include <string>
#include <list>
using namespace std;
class Subject;

//观察者 基类 (内部实例化了被观察者的对象sub)
class Observer {
protected:
	string name;
	Subject *sub;
public:
	Observer(string name, Subject *sub) {
		this->name = name;
		this->sub = sub;
	}
	virtual void update() = 0;
};

class StockObserver : public Observer {
public:
	StockObserver(string name, Subject *sub) : Observer(name, sub){}
	void update();
};

class NBAObserver : public Observer {
public:
	NBAObserver(string name, Subject *sub) : Observer(name, sub){}
	void update();
};

//被观察者 基类 (内部存放了所有的观察者对象,以便状态发⽣变化时,给观察者发通知)
class Subject {
protected:
	std::list<Observer *> observers;
public:
	string action; //被观察者对象的状态
	virtual void attach(Observer *) = 0;
	virtual void detach(Observer *) = 0;
	virtual void notify() = 0;
};

class Secretary : public Subject {
	void attach(Observer *observer) {
		observers.push_back(observer);
	}
	void detach(Observer *observer) {
		list<Observer *>::iterator iter = observers.begin();
		while (iter != observers.end()) {
			if ((*iter) == observer) {
			observers.erase(iter);
			return;
			}
			++iter;
		}
	}
	void notify() {
		list<Observer *>::iterator iter = observers.begin();
		while (iter != observers.end()) {
			(*iter)->update();
			++iter;
		}
	}
};
void StockObserver::update() {
	cout << name << " 收到消息:" << sub->action << endl;
	if (sub->action == "⽼板来了!") {
		cout << "我⻢上关闭股票,装做很认真⼯作的样⼦!" << endl;
	}
}
void NBAObserver::update() {
	cout << name << " 收到消息:" << sub->action << endl;
	if (sub->action == "⽼板来了!") {
		cout << "我⻢上关闭 NBA,装做很认真⼯作的样⼦!" << endl;
	}
}
int main()
{
	Subject *BOSS = new Secretary();
	Observer *xa = new NBAObserver("xa", BOSS);
	Observer *xb = new NBAObserver("xb", BOSS);
	Observer *xc = new StockObserver("xc", BOSS);
	BOSS->attach(xz);
	BOSS->attach(xb);
	BOSS->attach(xc);
	BOSS->action = "去吃饭了!";
	BOSS->notify();
	cout << endl;
	BOSS->action = "⽼板来了!";
	BOSS->notify();
	return 0; 
}
//输出
//product A create! product B create!

装饰器模式

装饰器模式(Decorator Pattern)允许向⼀个现有的对象添加新的功能,同时⼜不改变其结构。
这种类型的设计模式属于结构型模式,它是作为现有的类的⼀个包装。
如下代码中没有改变 Car 类的内部结构,还为其增加了新的功能,这就是装饰器模式的作⽤。

#include <iostream>
#include <list>
#include <memory>
using namespace std;
//抽象构件类 Transform (变形⾦刚)
class Transform{
public:
	virtual void move() = 0;
};

//具体构件类Car
class Car : public Transform{
public:
	Car(){
		std::cout << "变形⾦刚是⼀辆⻋!" << endl;
	}
	void move(){
		std::cout << "在陆地上移动。" << endl;
	}
};

//抽象装饰类
class Changer : public Transform{
public:
	Changer(shared_ptr<Transform> transform){
		this->transform = transform;
	}
	void move(){
		transform->move();
	}
private:
	shared_ptr<Transform> transform;
};

//具体装饰类Robot
class Robot : public Changer{
public:
	Robot(shared_ptr<Transform> transform) : Changer(transform){
		std::cout << "变成机器⼈!" << std::endl;
	}
	void say(){
		std::cout << "说话!" << std::endl;
	}
};

//具体装饰类AirPlane
class Airplane : public Changer{
public:
	Airplane(shared_ptr<Transform> transform) : Changer(transform){
		std::cout << "变成⻜机!" << std::endl;
	}
	void say(){
		std::cout << "在天空⻜翔!" << std::endl;
	} 
};
int main(void){
	shared_ptr<Transform> camaro = make_shared<Car>();
	camaro->move();
	std::cout << "--------------" << endl;
	shared_ptr<Robot> bumblebee = make_shared<Robot>(camaro);
	bumblebee->move();
	bumblebee->say();
   	std::cout << "--------------" << endl;
	shared_ptr<Airplane> bumblebee1 = make_shared<Airplane>(camaro);
	bumblebee1->move();
	bumblebee1->say();
	return 0;
}
/*
输出
变形⾦刚是⼀辆⻋!
在陆地上移动。
--------------
变成机器⼈!
在陆地上移动。
说话!
--------------
变成⻜机!
在陆地上移动。
在天空⻜翔!
*/

装饰器模式的优点:

1、可以轻松对已存在的对象进行修改和包装,在被装饰者的前面或者后面添加自己的行为,而无需修改原对象。

2、可以动态、不限量地进行装饰,可以更灵活地扩展功能。

相对地,装饰器模式有很明显的缺点:

1、会加入大量的小类,即使只添加一个功能,也要额外创建一个类,使得程序更复杂。

2、增加代码复杂度,使用装饰器模式不但需要实例化组件,还要把组件包装到装饰者中。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

常用设计模式总结 的相关文章

  • 使用 CLion 进行 OpenCV Windows 设置

    我想在 Windows 上为 CLion IDE 设置 OpenCV 我尝试使用 OpenCV 3 1 和 2 4 得到相同的结果 我有 Windows 10 64 位 CLion 使用 cygwin 环境 到目前为止我做了什么 1 从Op
  • 多个源的 makefile

    在学习 make 文件时 我试图为多个源目录编写一个 make 文件 似乎我在某个地方错了 这是我的代码结构 directory common fun2 c inc fun h src fun1 c main c 这是我的生成文件 CC c
  • 添加 Nullable int 时保持 null?

    我想添加可为空的int 并保留null当所有值都是null 我想要这个结果 1 2 3 1 null 1 null null null O null 0 问题是 如果我将一个值与 null 相加 结果为 null int i1 1 int
  • 如何在另一个应用程序中挂钩 api 调用

    我正在尝试挂钩另一个应用程序的 ExtTextOut 和 DrawTextExt GDI 方法调用 我知道我需要使用 GetProcAddress 来查找 gdi32 dll 中那些方法的地址 并用我的函数的地址覆盖我想要挂钩的进程中的地址
  • 删除是如何工作的? [复制]

    这个问题在这里已经有答案了 可能的重复 C 编程 free 如何知道要释放多少 https stackoverflow com questions 1518711 c programming how does free know how m
  • 使用查询表达式对 List 进行排序

    我在使用 Linq 订购这样的结构时遇到问题 public class Person public int ID get set public List
  • MFC:如何设置CEdit框的焦点?

    我正在开发我的第一个简单的 MFC 项目 但我正在努力解决一个问题 想要设置所有的焦点CEdit其中一个对话框中的框 我的想法是 当打开对话框时 焦点位于第一个编辑框上 然后使用 选项卡 在它们之间交换 我看到了方法SetFocus 但我无
  • 根据对象变量搜索对象列表

    我有一个对象列表 这些对象具有三个变量 ID 名称和值 这个列表中可能有很多对象 我需要根据ID或Name找到一个对象 并更改值 例子 class objec public string Name public int UID public
  • C#6 中的长字符串插值行

    我发现 虽然字符串插值在应用于现有代码库的字符串 Format 调用时非常好 但考虑到通常首选的列限制 字符串对于单行来说很快就会变得太长 特别是当被插值的表达式很复杂时 使用格式字符串 您将获得一个可以拆分为多行的变量列表 var str
  • 搜索实体的所有字段

    我正在尝试在客户数据库上实现 多功能框 类型的搜索 其中单个查询应尝试匹配客户的任何属性 这是一些示例数据来说明我想要实现的目标 FirstName LastName PhoneNumber ZipCode Mary Jane 12345
  • 引用/指针失效到底是什么?

    我找不到任何定义指针 引用无效在标准中 我问这个问题是因为我刚刚发现 C 11 禁止字符串的写时复制 COW 据我了解 如果应用了 COW 那么p仍然是一个有效的指针并且r以下命令后的有效参考 std string s abc std st
  • 从BackgroundWorker线程更新图像UI属性

    在我正在编写的 WPF 应用程序中 我有一个 TransformedBitmap 属性 该属性绑定到 UI 上的 Image 对象 每当我更改此属性时 图像就会更新 因此显示在屏幕上的图像也会更新 为了防止在检索下一张图像时 UI 冻结或变
  • Project Euler #8,我不明白我哪里出了问题[关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 我正在做项目欧拉第八题 https projecteuler net problem 8 其中我得到了这个大得离谱的数字 7316
  • 使用 GCC 生成可读的程序集?

    我想知道如何使用GCC http en wikipedia org wiki GNU Compiler Collection在我的 C 源文件中转储机器代码的助记符版本 这样我就可以看到我的代码被编译成什么 你可以使用 Java 来做到这一
  • 如何停止无限循环?

    我正在编写一个程序 该程序将计算三角形或正方形的面积 然后提示用户是否希望计算另一个 我的代码已经运行到可以计算任一形状的面积的程度 但随后不再继续执行代码的其余部分 例如 如果选择了正方形 则计算面积 然后返回到正方形边长的提示 我假设这
  • 如何在 winforms 应用程序的主屏幕显示之前显示欢迎屏幕?

    我想在应用程序启动时加载欢迎屏幕 然后用户单击欢迎屏幕上的按钮 然后关闭欢迎屏幕 最后显示主屏幕 static void Main startup method being called Application EnableVisualSt
  • 通过 Tab 键浏览 XML 文档字段

    In VB NET you can move through the fields in the XML member documentation with the Tab key 这在 C 中不起作用 还有其他方法吗 除了用鼠标将光标放在
  • 来自 3rd 方库的链接器错误 LNK2019

    我正在将旧的 vc 6 0 应用程序移植到 vs2005 我收到以下链接器错误 我花了几天时间试图找到解决方案 错误LNK2019 无法解析的外部符号 imp 创建AwnService 52 在函数 public int thiscall
  • DataContractSerializer 事件/委托字段问题

    在我的 WPF 应用程序中 我正在使用DataContractSerializer序列化对象 我发现它无法序列化具有事件或委托声明的类型 考虑以下失败的代码 Serializable public abstract class BaseCl
  • 为什么匹配模板类上的部分类模板特化与没有模板匹配的另一个部分特化不明确?

    这个问题可能很难用标题中的句子来描述 但这里有一个最小的例子 include

随机推荐

  • QT信号与槽的自动连接

    信号与槽的自动连接 信号与槽可以通过使用手写代码显式的实现关联 也可以运用 QMetaObject 类规定的槽 函数命名范式来实现自动关联 显式关联 首先我们来看一下 不使用 自动关联规则 的情形 在下面这段代码里面 我们定义了一个对话框类
  • 48、Flutter之widgets LayoutBuilder组件

    LayoutBuilder 通过 LayoutBuilder 我们可以在布局过程中拿到父组件传递的约束信息 然后我们可以根据约束信息动态的构建不同的布局 比如我们实现一个响应式的 Column 组件 ResponsiveColumn 它的功
  • jquery筛选器

    在Web应用程序中 大部分的客户端操作都是基于对象的操作 要操作对象就必须先获取对象 jQuery提供了强大的选择器让我们获取对象 我人为地将jQuery选择器分为两大部分 选择对象和筛选条件 选择对象表示要获取什么对象 筛选条件是对获取的
  • # 2023 好用免费图床推荐

    1 聚合图床 该免费图床由来已久 稳定运行多年 满足多种个性化需要 可以说该图床是所有推荐当中最为灵活 扩展性最强图床 支持水印设置 防盗链设置 甚至还可以统计数据量大小 有普通用户和付费用户区分 付费用户自定义功能将更加强大 就个人而言
  • Spring Cloud Config配置服务及那些你不知道的坑

    目录 1 为什么选择Spring Cloud Config 1 1 集中式管理 1 2 动态修改配置 2 Spring Cloud Config 简介 3 服务端配置 3 1 添加依赖 3 2 开启服务注册 3 3 添加YML配置 3 4
  • springboot结合aop和pagehelper实现分页筛选排序功能

    一 前言 首先我们要知道什么是aop 什么是pagehelper 从而我们知道 pagehelper的实现其实是两行代码 PageHelper startPage pageNum pageSize 开始分页 PageInfo pageInf
  • Python中class的内置函数__str__

    Python中class的内置函数 str 一 说明 init 类实例初始化函数 str 类实例字符串化函数 二 示例1 1 2 3 4 5 6 class Fri
  • Java并发编程学习2-线程安全性

    Java并发编程学习系列 线程安全性 引言 1 什么是线程安全性 1 1 如何编写线程安全的代码 1 2 线程安全类 1 3 无状态对象 2 原子性 2 1 竞态条件 2 2 延迟初始化 2 3 复合操作 3 加锁机制 3 1 内置锁 3
  • 华为OD机试 - 根据某条件聚类最少交换次数(Java)

    目录 题目描述 输入描述 输出描述 用例 题目解析 算法源码 题目描述 给出数字K 请输出所有结果小于K的整数组合到一起的最少交换次数 组合一起是指满足条件的数字相邻 不要求相邻后在数组中的位置 数据范围 100 lt K lt 100 1
  • 编写程序,生成一个包含50个随机整数的列表,然后删除奇数

    可以这样编写程序 list for i in range 50 list append random randint 1 100 for num in list if num 2 0 list remove num print list
  • latex入门学习笔记总结

    目录 latex文件的组织方式 latex中的字符 latex中的强调 latex中的分页和断行 latex中文档元素 latex的环境 列表环境 代码环境 htbp 命令 latex中的表格 latex中的图片 插入一张图片 两图并排 插
  • linux指令timedatectl,centos7设置时间命令timedatectl

    在新的centos7里 关于时间的指令除了保留了之前版本中常用到的date hwclock等命令外 还增加了一个统一的命令timedatactl 下面结合其用法进行下小结 查看 timedatectl 指令用法帮助 root 361way
  • WPF自学篇--第一篇--Hello world

    主要知识点为 1 WPF如何修改启动页面 2 如何写Hello Word Sample 内容 1 由于专案是先加window wpf想加web wpf是调试找启动页面找了很久 终于发现在app config中Application下 Sta
  • python LeetCode 88 刷题记录

    题目 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2 另有两个整数 m 和 n 分别表示 nums1 和 nums2 中的元素数目 请你 合并 nums2 到 nums1 中 使合并后的数组同样按 非递减顺序 排列 注意
  • 修改Windows系统注册表并使其立即生效

    title 修改Windows系统注册表并使其立即生效 update 2019 12 22 15 38 06 description 修改Windows系统注册表并使其立即生效的方法 原文地址https tomsworkspace gith
  • 日常生活中常用的五星级句子

    1 After you 你先请 这是一句很常用的客套话 在进 出门 上车得场合你都可以表现一下 好象现在女士不愿意你这么做 特别是那些女权主义者 我还记得这么一段话 一个女士对一个让她先行的男士说 you do this because i
  • 基础版图书管理系统(Java实现)

    文章目录 前言 一 设计书类 书架类 二 设计用户类 1 管理员 2 普通用户 三 操作包 前言 对于图书管理系统我想大家都不会陌生 在C语言的学习中相信大家都写过这个系统 那么今天我们就用Java来实现一下图书管理系统 看看和C语言又有什
  • Linux下查看目录文件数和文件大小

    一 查看当前目录下文件个数 在linux下查看目录下有多少文件可以用 ls l 命令查看 ls lR 递归查看所有目录 如果文件很多 则用wc命令 和 grep 命令进行过滤 wc命令显示输出的行 列 字符数 l表示仅列出行 w表示仅列出多
  • Typescript:类的装饰器

    Typescript的装饰器我在学习typescript的时候并不是很清楚它的作用场景 直到使用了nest js框架后 才明白其作用 于是又深入学习了一下 希望通过对装饰器的学习提高对nest js的使用 装饰器 装饰器为我们在类的声明及成
  • 常用设计模式总结

    设计模式的相关知识 很多书籍和博客中都有详细总结 本文总结的目的 1 将自己学习到的设计模式的知识按照自己的逻辑重新总结 方便查看和记忆 2 方便让自己对设计模式中常用的知识有一个系统的认知 设计模式 话设计模式 书中提到 24 种设计模式