自学设计模式(类图、设计原则、单例模式 - 饿汉/懒汉)

news2024/12/22 19:46:58

设计模式需要用到面向对象的三大特性——封装、继承、多态(同名函数具有不同的状态)

UML类图 eg.—— 描述类之间的关系(设计程序之间画类图)

 +: public; #: protected; -: private; 下划线: static

属性名:类型(=默认值)

方法和变量分开-------

虚函数斜体,纯虚函数在虚函数类型后=0,并且类名斜体

类与类之间的关系:

1. 继承关系(空心三角形实线,箭头指父类)

2. 关联关系(单项关联、双向关联、自关联 - 链表)用带箭头和不带箭头的实现

3. 聚合关系(整体与部分的关系,整体析构部分不析构)空心菱形实线链接,指向整体

4. 组合关系(整体析构部分析构)实心菱形实线链接

5. 依赖关系(使用关系)带箭头的虚线,指向被依赖方

类之间的关系强弱:继承(泛化)>组合>聚合>关联>依赖(类图按类间最强关系就可)

设计模式三原则

单一职责原则(面向对象):

使得类的功能尽量单一,方便管理维护,避免类的臃肿。

开放封闭原则:

对于扩展是开放的,对于修改是封闭的,增加程序可维护性可扩展性。

依赖转换原则:

高层模块不应该依赖低层模块(应用程序不直接调用API),两个都应该依赖抽象。

抽象不依赖细节,细节应该依赖抽象。(里氏代换原则)

单例模式和任务队列(类的对象只能创建出一个)

一个项目中,全局范围内,某个类的实例有且仅有一个,通过这个实例向其他模块提供数据的全局访问。(简介访问实现对于变量的保护)

将类的默认构造函数和拷贝构造函数设为private,或者将两个函数=delete;

使类无法在外面创建对象,只能通过类名访问静态属性或者方法;

懒汉模式和饿汉模式

饿汉模式——定义类的时候创建单例对象(多线程下没有线程安全问题)

// 饿汉模式
#include <bits/stdc++.h>
using namespace std;

class A{
public:
	A(const A& a) = delete;
	A& operator =(const A& a) = delete;
	static A* get(){
		return num;
	}
	print(){
		cout<<"单例模式的唯一实例";
	}
private:
	A() = default; // 默认构造 
	static A* num;
};

A* A::num = new A;

int main(){
	A* a = A::get();
	a->print(); 
	return 0;
} 

懒汉模式——什么时候使用单例对象再去创建实例(多线程下存在线程安全问题)

// 懒汉模式
#include <bits/stdc++.h>
using namespace std;

class A{
public:
	A(const A& a) = delete;
	A& operator =(const A& a) = delete;
	static A* get(){
        num = new A;
		return num;
	}
	print(){
		cout<<"单例模式的唯一实例";
	}
private:
	A() = default; // 默认构造 
	static A* num;
};

A* A::num = nullptr;

int main(){
	A* a = A::get();
	a->print(); 
	return 0;
} 

懒汉模式的线程安全问题

可以通过双重检查锁定解决懒汉模式的线程安全问题:1. 互斥锁(导致效率低) 2. 实例创建判定

// 懒汉模式
#include <bits/stdc++.h> 
using namespace std;

class A{
public:
	A(const A& a) = delete;
	A& operator =(const A& a) = delete;
	static A* get(){ // first check
		if(num==nullptr){
			lk.lock();
			if(num==nullptr)num = new A; // second check 
			lk.unlock();
		}
		return num;
	}
	print(){
		cout<<"单例模式的唯一实例";
	}
private:
	A() = default; // 默认构造 
	static A* num;
	static mutex lk;
};

A* A::num = nullptr;
mutex A::lk;

int main(){
	A* a = A::get();
	a->print(); 
	return 0;
} 

通过原子变量(atomic - 底层控制机器指令执行顺序)解决双重检查锁定的问题;放置底层的机器指令不按理想顺序执行

// 懒汉模式
#include <bits/stdc++.h> 
using namespace std;

class A{
public:
	A(const A& a) = delete;
	A& operator =(const A& a) = delete;
	static A* get(){ // first check
		A* cur = task.load();
		if(cur==nullptr){
			lk.lock();
			cur = task.load();
			if(cur==nullptr){
				cur = new A; // second check
				task.store(cur);
			} 
			lk.unlock();
		}
		return cur;
	}
	print(){
		cout<<"单例模式的唯一实例";
	}
private:
	A() = default; // 默认构造 
	static A* num;
	static mutex lk;
	static atomic<A*> task;
};

A* A::num = nullptr;
mutex A::lk;
atomic<A*> A::task;

int main(){
	A* a = A::get();
	a->print(); 
	return 0;
} 

使用静态局部对象解决线程安全问题

#include <bits/stdc++.h> 
using namespace std;

class A{
public:
	A(const A& a) = delete;
	A& operator =(const A& a) = delete;
	static A* get(){ // first check
		static A a;
		return &a; 
	}
	print(){
		cout<<"单例模式的唯一实例";
	}
private:
	A() = default; // 默认构造 
};

int main(){
	A* a = A::get();
	a->print(); 
	return 0;
} 

并发执行应当等待变量完成初始化;

总结

1. 饿汉模式不存在线程安全问题

2. 懒汉模式通过双重检查锁定+原子变量或者静态局部对象(简单)可以解决线程安全问题       

实践(多线程模式下的任务模型)

#include <bits/stdc++.h>
using namespace std;


// 饿汉模式
#include <bits/stdc++.h>
using namespace std;

class A{
public:
	A(const A& a) = delete;
	A& operator =(const A& a) = delete;
	static A* get(){
		return num;
	}
	print(){
		cout<<"单例模式的唯一实例";
	}
	
	bool isempty(){
		lock_guard<mutex> locker(m_mutex);
		return mis.empty(); 
	}
	
	void add_m(int node){
		lock_guard<mutex> locker(m_mutex);
		mis.push(node);
	}
	
	bool minus_m(){
		lock_guard<mutex> locker(m_mutex);
		if(mis.empty())return false;
		else{
			mis.pop();
		}
		return true;
	}
	
	int get_m(){
		lock_guard<mutex> locker(m_mutex);
		if(mis.empty())return -1;
		return mis.front();	
	}
private:
	A() = default; // 默认构造 
	static A* num;
	queue<int> mis;
	mutex m_mutex;
};

A* A::num = new A;

int main(){
	A *a = A::get();
	
	// 生产者
	thread t1([=](){
		for(int i = 0 ; i<10 ; i++){
			a->add_m(i+100);
			cout<<"push data: "<<i+100<<" "<<"threadId: "<<this_thread::get_id()<<endl;
			this_thread::sleep_for(chrono::milliseconds(500));
		} 
	});

	// 消费者 
	thread t2([=](){
		this_thread::sleep_for(chrono::milliseconds(100));
		while(!a->isempty()){
			int cur = a->get_m();
			cout<<"take data: "<<cur<<" "<<"threadId: "<<this_thread::get_id()<<endl;
			a->minus_m();
			this_thread::sleep_for(chrono::milliseconds(1000));
		} 
	});
	
	// 阻塞主线程 
	t1.join();
	t2.join();
	
	return 0;
} 

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

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

相关文章

如果将PC电脑变成web服务器:利用Nignx反向代理绕过运营商对80端口封锁

如果将PC电脑变成web服务器&#xff1a;利用Nignx反向代理绕过运营商对80端口封锁 在上一篇文章中&#xff0c;我们已经实现了内网主机的多次端口映射&#xff0c;将内网主机的端口映射到了公网&#xff0c;可以通过公网访问该主机了。 因为电信的家庭宽带&#xff0c;默认是…

SpringBoot读取Nacos配置文件

断点到ClientWorker类的getServerConfig方法&#xff0c;反向Debug。

2023-8-23 Trie字符串统计

题目链接&#xff1a;Trie字符串统计 #include <iostream>using namespace std;const int N 100010;int son[N][26], cnt[N],idx;char str[N];void insert(char str[]) {int p 0;for(int i 0; str[i]; i){int u str[i] - a;if(!son[p][u]) son[p][u] idx;p son[p…

Langchain+LLM

LangChain是一个开源框架&#xff0c;允许开发人员在与人工智能&#xff08;AI&#xff09;一起工作时将大型语言模型&#xff08;如GPT4&#xff09;与外部计算和数据源相结合&#xff08;它提供了一套工具、组件和接口&#xff0c;可简化创建由LLM提供支持的应用程序&#xf…

前端进阶Html+css09----BFC模型

1.什么是BFC模型 全称是&#xff1a;Block formatting context&#xff08;块级格式化上下文&#xff09;&#xff0c;是一个独立的布局环境&#xff0c;不受外界的影响。 2.FC,BFC,IFC 元素在标准流里都属于一个FC&#xff08;Formatting Context&#xff09;。 块级元素的布…

【图像分割】理论篇(2)经典图像分割网络基于vgg16的Unet

UNet 是一种用于图像分割任务的深度学习架构&#xff0c;最早由 Olaf Ronneberger、Philipp Fischer 和 Thomas Brox 在2015年的论文 "U-Net: Convolutional Networks for Biomedical Image Segmentation" 中提出。UNet 在医学图像分割等领域取得了显著的成功&#x…

Anaconda安装教程以及深度学习环境搭建

目录 前言 下载Anaconda 虚拟环境的搭建 在pycharm中配置现有的conda环境 CUDA简介 下载安装pytorch包 前言 最近换新笔记本了&#xff0c;要重新安装软件&#xff0c;以前本来是想要写这个教程的&#xff0c;但当时由于截图不全还要懒得再下载重装&#xff0c;就放弃了&…

JavaSE【继承和多态】(1)(重点:初始化、pretected封装、组合)

一、继承 继承 (inheritance) 机制 &#xff1a;是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特 性 的基础上进行扩展&#xff0c;增加新功能 &#xff0c;这样产生新的类&#xff0c;称 派生类 。 继承呈现了面向对象程序设计的层次结…

TRON归集回调

简介 设计一个通过调用api创建对应的tron地址&#xff0c;当地址收到token的时候&#xff0c;进行归集&回调通知的。包括的功能有: 根据UID创建地址归集&#xff08;TRX归集 TRC10归集 TRC20归集)回调通知&#xff08;转出回调通知&接收回调通知&#xff09;发起转出…

什么是JVM ?

一、JVM 简介 JVM 是 Java Virtual Machine 的简称&#xff0c;意为 Java 虚拟机。 虚拟机是指通过软件模拟的具有完整硬件功能的、运行在一个完全隔离的环境中的完整计算机系统。 常见的虚拟机&#xff1a; JVM 、 VMwave 、 Virtual Box 。 JVM 和其他两个虚拟机的区别…

《JVM修仙之路》初入JVM世界

《JVM修仙之路》初入JVM世界 博主目前正在学习JVM的相关知识&#xff0c;想以一种不同的方式记录下&#xff0c;娱乐一下 清晨&#xff0c;你睁开双眼&#xff0c;看到刺眼的阳光&#xff0c;你第一反应就是完了完了&#xff0c;又要迟到了。刚准备起床穿衣的你突然意识到不对&…

Netty核心源码解析(三)--NioEventLoop

NioEventLoop介绍 NioEventLoop继承SingleThreadEventLoop,核心是一个单例线程池,可以理解为单线程,这也是Netty解决线程并发问题的最根本思路--同一个channel连接上的IO事件只由一个线程来处理,NioEventLoop中的单例线程池轮询事件队列,有新的IO事件或者用户提交的task时便执…

Centos7 安装Docker 详细多图版

配置要求 Docker CE&#xff08;社区免费版&#xff09; 支持 64 位版本 CentOS 7&#xff0c;并且要求内核版本不低于 3.10&#xff0c; CentOS 7 满足最低内核的要求&#xff0c;所以我们在CentOS 7安装Docker。 一、Centos安装Docker 1.1 卸载&#xff08;可选&#xff0…

项目:点餐系统2

httplib的思想简单总结; 使用线程池来处理请求由用户定义处理函数&#xff0c;告诉httplib哪个请求应该使用哪个函数处理线程接收请求并解析请求后调用处理函数 一、服务器搭建 get主要是用来获取资源的&#xff0c;post主要是客户端提交数据的。 #include"httplib.h"…

小白带你学习linux的shell脚本基础(三十五)

目录 一、概述 1、脚本就是将手动一次性执行的命令进行规范且自动化 2、学习路径 2.1表达式 2.2语句 2.3函数 2.4正则表达式 2.5文件操作四剑客 二、表达式 1、shell 2、表达式 2、1 变量 2、2 运算符 2、3shell脚本编写规范 2、4shell运行规则 2、5shell脚本运…

SpringSecurity原理

最近在研究SpringSecurity&#xff0c;肝了好多天&#xff0c;算是有点收获&#xff0c;在这里分享下 SpringSecurity是什么&#xff1f; SpringSecurity是一个强大的可高度定制的认证和授权框架&#xff0c;对于Spring应用来说它是一套Web安全标准。SpringSecurity注重于为J…

数据结构:直接插入排序,希尔排序,选择排序,堆排序,冒泡排序,快速排序,归并排序,计数排序(C实现)

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》 文章目录 前言一、插入排序1.直接插入排序2.希尔排序 二、选择排序1. 选择排序2.堆排序 三、交换排序1.冒泡排序2.快速排序(递归)a.hoare版(PartSort1)b.挖坑法(PartSort2)c.前后指针法(PartSort…

基于引力搜索算法优化的BP神经网络(预测应用) - 附代码

基于引力搜索算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录 基于引力搜索算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍2.引力搜索优化BP神经网络2.1 BP神经网络参数设置2.2 引力搜索算法应用 4.测试结果&#xff1a;5…

Mr. Cappuccino的第64杯咖啡——Spring循环依赖问题

Spring循环依赖问题 什么是循环依赖问题示例项目结构项目代码运行结果 Async注解导致的问题使用Lazy注解解决Async注解导致的问题开启Aop使用代理对象示例项目结构项目代码运行结果 Spring是如何解决循环依赖问题的原理源码解读 什么情况下Spring无法解决循环依赖问题 什么是循…

nginx部署 vue配置代理服务器 解决跨域问题

为了演示方便使用的是windows部署 1.首先将vue打包 2.打包好的vue放入到nginx-1.24.0\html\下,这里我创建一个big-data文件夹所以放入到big-data方便多项目管理 3.打开nginx.conf的配置文件修改 server {listen 8081;server_name localhost;location /{alias html/big-data…