【3】基于多设计模式下的同步异步日志系统-设计模式
详细介绍设计模式
单例模式
⼀个类只能创建⼀个对象,即单例模式,该设计模式可以保证系统中该类只有⼀个实例,并提供⼀个访问它的全局访问点,该实例被所有程序模块共享。⽐如在某个服务器程序中,该服务器的配置信息存放在⼀个⽂件中,这些配置数据由⼀个单例对象统⼀读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种⽅式简化了在复杂环境下的配置管理。
单例模式有两种实现模式:饿汉模式和懒汉模式
饿汉模式
程序启动时就会创建⼀个唯⼀的实例对象。 因为单例对象已经确定, 所以⽐较适⽤于多线程环境中, 多线程获取单例对象不需要加锁, 可以有效的避免资源竞争, 提⾼性能。
// 饿汉模式
template<typename T>
class Singleton {
private:static Singleton _eton;
private:Singleton(){}~Singleton(){}
public:Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;static T& getInstance() {return _eton;}
};
Singleton Singleton::_eton;
懒汉模式
第⼀次使⽤要使⽤单例对象的时候创建实例对象。如果单例对象构造特别耗时或者耗费济源(加载插件、加载⽹络资源等), 可以选择懒汉模式, 在第⼀次使⽤的时候才创建对象。
这⾥介绍的是《Effective C++》⼀书作者 Scott Meyers 提出的⼀种更加优雅简便的单例模式Meyers’ Singleton in C++。
C++11 Static local variables 特性以确保C++11起,静态变量将能够在满⾜ thread-safe 的前提下唯⼀地被构造和析构
// 懒汉模式
template <typename T>
class Singleton {
private:Singleton(){}~Singleton(){}
public: Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;static T& getInstance() { static Singleton _eton;return _eton; }
};
工厂模式
⼯⼚模式是⼀种创建型设计模式, 它提供了⼀种创建对象的最佳⽅式。在⼯⼚模式中,我们创建对象时不会对上层暴露创建逻辑,⽽是通过使⽤⼀个共同结构来指向新创建的对象,以此实现创建-使⽤的分离。
工厂模式可以分为:简单工厂模式,工厂方法模式,抽象工厂模式。
简单工厂模式
简单⼯⼚模式实现由⼀个⼯⼚对象通过类型决定创建出来指定产品类的实例。假设有个⼯⼚能⽣产出⽔果,当客⼾需要产品的时候明确告知⼯⼚⽣产哪类果,⼯⼚需要接收⽤⼾提供的类别信息,当新增产品的时候,⼯⼚内部去添加新产品的⽣产⽅式。
//简单⼯⼚模式:通过参数控制可以⽣产任何产品
// 优点:简单粗暴,直观易懂。使⽤⼀个⼯⼚⽣产同⼀等级结构下的任意产品
// 缺点:
// 1. 所有东西⽣产在⼀起,产品太多会导致代码量庞⼤
// 2. 开闭原则遵循(开放拓展,关闭修改)的不是太好,要新增产品就必须修改⼯⼚⽅法。
#include <iostream>
#include <string>
#include <memory>
class Fruit {public:Fruit(){}virtual void show() = 0;
};
class Apple : public Fruit {public:Apple() {}virtual void show() {std::cout << "我是⼀个苹果" << std::endl;}
};
class Banana : public Fruit {public:Banana() {}virtual void show() {std::cout << "我是⼀个⾹蕉" << std::endl;}
};
class FruitFactory {public:static std::shared_ptr<Fruit> create(const std::string &name) {if (name == "苹果") {return std::make_shared<Apple>();}else if(name == "⾹蕉") {return std::make_shared<Banana>();}return std::shared_ptr<Fruit>();}
};
int main()
{std::shared_ptr<Fruit> fruit = FruitFactory::create("苹果");fruit->show();fruit = FruitFactory::create("⾹蕉");fruit->show();return 0;
}
这个模式的结构和管理产品对象的⽅式⼗分简单, 但是它的扩展性⾮常差,当我们需要新增产品的时候,就需要去修改⼯⼚类新增⼀个类型的产品创建逻辑,违背了开闭原则。
工厂方法模式
在简单⼯⼚模式下新增多个⼯⼚,多个产品,每个产品对应⼀个⼯⼚。假设现在有
A、B 两种产品,则开两个⼯⼚,⼯⼚ A 负责⽣产产品 A,⼯⼚ B 负责⽣产产品 B,⽤⼾只知道产品
的⼯⼚名,⽽不知道具体的产品信息,⼯⼚不需要再接收客⼾的产品类别,⽽只负责⽣产产品。
#include <iostream>
#include <string>
#include <memory>
//⼯⼚⽅法:定义⼀个创建对象的接⼝,但是由⼦类来决定创建哪种对象,使⽤多个⼯⼚分别⽣产指定
的固定产品
// 优点:
// 1. 减轻了⼯⼚类的负担,将某类产品的⽣产交给指定的⼯⼚来进⾏
// 2. 开闭原则遵循较好,添加新产品只需要新增产品的⼯⼚即可,不需要修改原先的⼯⼚类
// 缺点:对于某种可以形成⼀组产品族的情况处理较为复杂,需要创建⼤量的⼯⼚类.
class Fruit {public:Fruit(){}virtual void show() = 0;
};
class Apple : public Fruit {public:Apple() {}virtual void show() {std::cout << "我是⼀个苹果" << std::endl;}private:std::string _color;
};
class Banana : public Fruit {public:Banana() {}virtual void show() {std::cout << "我是⼀个⾹蕉" << std::endl;}
};
class FruitFactory {public:virtual std::shared_ptr<Fruit> create() = 0;
};
class AppleFactory : public FruitFactory {public:virtual std::shared_ptr<Fruit> create() {return std::make_shared<Apple>();}
};
class BananaFactory : public FruitFactory {public:virtual std::shared_ptr<Fruit> create() {return std::make_shared<Banana>();}
};
int main()
{std::shared_ptr<FruitFactory> factory(new AppleFactory());fruit = factory->create();fruit->show();factory.reset(new BananaFactory());fruit = factory->create();fruit->show();return 0;
}
⼯⼚⽅法模式每次增加⼀个产品时,都需要增加⼀个具体产品类和⼯⼚类,这会使得系统中类的个数成倍增加,在⼀定程度上增加了系统的耦合度。
抽象工厂模式
⼯⼚⽅法模式通过引⼊⼯⼚等级结构,解决了简单⼯⼚模式中⼯⼚类职责太重的问题,但由于⼯⼚⽅法模式中的每个⼯⼚只⽣产⼀类产品,可能会导致系统中存在⼤量的⼯⼚类,势必会增加系统的开销。此时,我们可以考虑将⼀些相关的产品组成⼀个产品族(位于不同产品等级结构中功能相关联的产品组成的家族),由同⼀个⼯⼚来统⼀⽣产,这就是抽象⼯⼚模式的基本思想。
#include <iostream>
#include <string>
#include <memory>
//抽象⼯⼚:围绕⼀个超级⼯⼚创建其他⼯⼚。每个⽣成的⼯⼚按照⼯⼚模式提供对象。
// 思想:将⼯⼚抽象成两层,抽象⼯⼚ & 具体⼯⼚⼦类, 在⼯⼚⼦类种⽣产不同类型的⼦产品
class Fruit {public:Fruit(){}virtual void show() = 0;
};
class Apple : public Fruit {public:Apple() {}virtual void show() {std::cout << "我是⼀个苹果" << std::endl;}private:std::string _color;
};
class Banana : public Fruit {public:Banana() {}virtual void show() {std::cout << "我是⼀个⾹蕉" << std::endl;}
};
class Animal {public:virtual void voice() = 0;
};
class Lamp: public Animal {public:void voice() { std::cout << "咩咩咩\n"; }
};
class Dog: public Animal {public:void voice() { std::cout << "汪汪汪\n"; }
};
class Factory {public:virtual std::shared_ptr<Fruit> getFruit(const std::string &name) = 0;virtual std::shared_ptr<Animal> getAnimal(const std::string &name) = 0;
};
class FruitFactory : public Factory {public:virtual std::shared_ptr<Animal> getAnimal(const std::string &name) {return std::shared_ptr<Animal>();}virtual std::shared_ptr<Fruit> getFruit(const std::string &name) {if (name == "苹果") {return std::make_shared<Apple>();}else if(name == "⾹蕉") {return std::make_shared<Banana>();}return std::shared_ptr<Fruit>();}
};
class AnimalFactory : public Factory {public:virtual std::shared_ptr<Fruit> getFruit(const std::string &name) {return std::shared_ptr<Fruit>();}virtual std::shared_ptr<Animal> getAnimal(const std::string &name) {if (name == "⼩⽺") {return std::make_shared<Lamp>();}else if(name == "⼩狗") {return std::make_shared<Dog>();}return std::shared_ptr<Animal>();}
};
class FactoryProducer {public:static std::shared_ptr<Factory> getFactory(const std::string &name) {if (name == "动物") {return std::make_shared<AnimalFactory>();}else {return std::make_shared<FruitFactory>();}}
};
int main()
{std::shared_ptr<Factory> fruit_factory = FactoryProducer::getFactory("⽔
果");std::shared_ptr<Fruit> fruit = fruit_factory->getFruit("苹果");fruit->show();fruit = fruit_factory->getFruit("⾹蕉");fruit->show();std::shared_ptr<Factory> animal_factory = FactoryProducer::getFactory("动
物");std::shared_ptr<Animal> animal = animal_factory->getAnimal("⼩⽺");animal->voice();animal = animal_factory->getAnimal("⼩狗");animal->voice();return 0;
}
抽象⼯⼚模式适⽤于⽣产多个⼯⼚系列产品衍⽣的设计模式,增加新的产品等级结构复杂,需要对原有系统进⾏较⼤的修改,甚⾄需要修改抽象层代码,违背了“开闭原则”。
建造者模式
建造者模式是⼀种创建型设计模式, 使⽤多个简单的对象⼀步⼀步构建成⼀个复杂的对象,能够将⼀个复杂的对象的构建与它的表⽰分离,提供⼀种创建对象的最佳⽅式。主要⽤于解决对象的构建过于复杂的问题。
建造者模式主要基于四个核⼼类实现:
• 抽象产品类:
• 具体产品类:⼀个具体的产品对象类
• 抽象Builder类:创建⼀个产品对象所需的各个部件的抽象接⼝
• 具体产品的Builder类:实现抽象接⼝,构建各个部件
• 指挥者Director类:统⼀组建过程,提供给调⽤者使⽤,通过指挥者来构造产品
#include<iostream>
#include<string>
#include<memory>class Computer//抽象电脑类
{public:Computer(){}void SetBoard(const std::string& Board){_board=Board;}void SetDisplay(const std::string& Display){_display=Display;}virtual void SetOs()=0;void showParamaters(){std::string param="Computer Paramaters:\n";param+="\tBoard:"+_board+"\n";param+="\tDisplay:"+_display+"\n";param+="\tOs:"+_os+"\n";std::cout<<param<<std::endl;}protected:std::string _board;//主板std::string _display;//显示器std::string _os;//操作系统
};class MacBook:public Computer//具体电脑类
{public: void SetOs() override{_os="Mac Os x12";}
};class Builder//抽象建造者类
{public: virtual void buildBoard(const std::string& board)=0;virtual void buildDisplay(const std::string& display)=0;virtual void buildOs()=0;virtual std::shared_ptr<Computer> Build()=0;
};class MacBookBuilder:public Builder//具体建造者类
{public:MacBookBuilder():_computer(new MacBook()){}void buildBoard(const std::string& board){_computer->SetBoard(board);}void buildDisplay(const std::string& display){_computer->SetDisplay(display);}virtual void buildOs(){_computer->SetOs();}std::shared_ptr<Computer> Build(){return _computer;}private:std::shared_ptr<Computer> _computer;//利用多态
};class Director//指挥者,产品必须按照某种顺序来生产
{public:Director(Builder* builder):_builder(builder){}void construct(const std::string& board,const std::string& display){//按顺序建造_builder->buildBoard(board);_builder->buildDisplay(display);_builder->buildOs();}private:std::shared_ptr<Builder> _builder;};int main()
{Builder* builder=new MacBookBuilder();std::unique_ptr<Director> director(new Director(builder));director->construct("英特尔","三星");std::shared_ptr<Computer> computer=builder->Build();computer->showParamaters();return 0;
}
代理模式
代理模式指代理控制对其他对象的访问, 也就是代理对象控制对原对象的引⽤。在某些情况下,⼀个对象不适合或者不能直接被引⽤访问,⽽代理对象可以在客⼾端和⽬标对象之间起到中介的作⽤。
代理模式的结构包括⼀个是真正的你要访问的对象(⽬标类)、⼀个是代理对象。⽬标对象与代理对象实现同⼀个接⼝,先访问代理类再通过代理类访问⽬标对象。
代理模式分为静态代理、动态代理:
静态代理指的是,在编译时就已经确定好了代理类和被代理类的关系。也就是说,在编译时就已经确定了代理类要代理的是哪个被代理类。
动态代理指的是,在运⾏时才动态⽣成代理类,并将其与被代理类绑定。这意味着,在运⾏时才能确定代理类要代理的是哪个被代理类。
以租房为例,房东将房⼦租出去,但是要租房⼦出去,需要发布招租启⽰, 带⼈看房,负责维修,这些⼯作中有些操作并⾮房东能完成,因此房东为了图省事,将房⼦委托给中介进⾏租赁。 代理模式实现:
/*房东要把⼀个房⼦通过中介租出去理解代理模式*/
#include <iostream>
#include <string>
class RentHouse {public:virtual void rentHouse() = 0;
};
/*房东类:将房⼦租出去*/
class Landlord : public RentHouse {public: void rentHouse() {std::cout << "将房⼦租出去\n";}
};
/*中介代理类:对租房⼦进⾏功能加强,实现租房以外的其他功能*/
class Intermediary : public RentHouse {
public:void rentHouse() {std::cout << "发布招租启⽰\n";std::cout << "带⼈看房\n";_landlord.rentHouse();std::cout << "负责租后维修\n";}private:Landlord _landlord;
};
int main()
{Intermediary intermediary;intermediary.rentHouse();return 0;
}
相关文章:
【3】基于多设计模式下的同步异步日志系统-设计模式
详细介绍设计模式 单例模式 ⼀个类只能创建⼀个对象,即单例模式,该设计模式可以保证系统中该类只有⼀个实例,并提供⼀个访问它的全局访问点,该实例被所有程序模块共享。⽐如在某个服务器程序中,该服务器的配置信息存放…...
Metasploit的使用和配置
预计更新 第一章 Metasploit的使用和配置 1.1 安装和配置Metasploit 1.2 Metasploit的基础命令和选项 1.3 高级选项和配置 第二章 渗透测试的漏洞利用和攻击方法 1.1 渗透测试中常见的漏洞类型和利用方法 1.2 Metasploit的漏洞利用模块和选项 1.3 模块编写和自定义 第三章 Me…...
测试用例的设计思路
接到提测单后要做的事情: 测试准备阶段 确认提测单内包含的文件、URL地址可以访问确认需求 (迭代目标、用户故事、用户愿望、问题反馈等)确认回归测试范围、更新测试范围、新增测试范围编写测试点思维导图,过程中有问题及时进行沟通与迭代相关人员约一个…...

HCIP——交换综合实验
一、实验拓扑图 二、实验需求 1、PC1和PC3所在接口为access,属于vlan2;PC2/4/5/6处于同一网段,其中PC2可以访问PC4/5/6;但PC4可以访问PC5,不能访问PC6 2、PC5不能访问PC6 3、PC1/3与PC2/4/5/6/不在同一网段 4、所有PC通…...

大学生如何搭建自己的网站
这篇是我在大一的时候,写过的一篇文章。 前言 作为一名大学生,我觉得搭建个人网站很有意义。 这篇博客讲述的是这个寒假,我是如何从零到搭建好个人网站的过程。我提供的主要是具体的思路,也附带了一些零零散散的细节。时间跨度…...
linux 路由表的优先级
[rootlocalhost cc]# ip rule list 0: from all lookup local 32765: from 10.0.19.24 lookup 4096 32766: from all lookup main 32767: from all lookup default 现在有 4 条路由规则,优先级是怎样的,0 代表最低优先级还是最高优先级 在 Linux 的 IP …...
毕业项目分享
大家好,今天给大家分享112个有趣的Python实战项目,可以直接拿来实战练习,涵盖机器学习、爬虫、数据分析、数据可视化、大数据等内容,建议关注、收藏。 项目名称 主要技术 2023招聘数据分析可视化系统爬虫 7种薪资预测模型 Flas…...

Android启动系列之进程杀手--lmkd
本文概要 这是Android系统启动的第三篇文章,本文以自述的方式来讲解lmkd进程,通过本文您将了解到lmkd进程在安卓系统中存在的意义,以及它是如何杀进程的。(文中的代码是基于android13) 我是谁 init:“大…...

tex中的边框
文章目录 利用tcolorbox宏包给公式加框 利用tcolorbox宏包 tcolorbox可以创建一个盒子的环境,例如: \documentclass{article} \usepackage{tcolorbox} \begin{document}\begin{tcolorbox}[left1cm, right1cm, top0.5cm, bottom0.5cm,colbackblue!10!wh…...
面试题库之JAVA基础篇(三)
final 被final修饰的类不可以被继承。被final修改的方法不可以被重写。被final修改的方法,jvm会尝试内联,以提高运行效率。被final修改的变量不可变,如果修改的是引用,那么引用不可变,引用指向的对象内容可变。被fin…...

CTF-虚拟机-QEMU-前置知识-操作流程与源码阅读
文章目录 总览内存PCI设备PCI配置空间前64个字节对应源码Memorry空间的BARIO空间的BAR MMIOPMIOIspci访问PCI设备配置空间中的Memory空间和IO空间MMIOPMIO QQM(qemu object model)简洁概要将 TypeInfo 注册 TypeImpl:ObjectClass的初始化&…...
java成神秘籍第一卷
前言 适合还没有入行小白学习,有些朋友会跑来问我这行的一些问题,下面算是详细系统的整理了一下啦。 全当是学习 复盘 整理 记录了 java成神秘籍第一卷 前言一 前提1 要不要考公,考编,考研2 语言选择3 就业岗位4 目标5 考不考虑…...
golang实现文件上传(高并发+分块+断点续传+加密)
运行视频 // todo 根据前端传递文件加密 func (s *FileProcess) FileProcessEncryptionByFront(file multipart.File, h *multipart.FileHeader) interface{} { //根据字节直接处理文件 这个是前端传递的二进制流s.FileProcessInit() //文件初始化 设置原来文件…...

用HeidiSQL在MySQL中新建用户
用HeidiSQL登录到MySQL数据库,注意登录的时候要使用有权限的用户: 选择工具-》用户管理: 点击左上角的“添加”: 输入用户名、密码,并且分配权限: 点击右边的“添加对象”: 可以根据自己…...

【IPv6】IPv6协议
一、IPv6数据报格式 这是与v4报头的对比 1.8bit的版本保留了,v4版本就是4,v6就是6。 2.v6去除了v4的首部长度字段,因为v6的首部长是固定的40字节。 3.服务类型(Type of Service, ToS)和通信类型(Traffi…...

无需服务器,无需魔法,拥有一个微信机器人就是这么简单
前情提要 还没看过的朋友可以看一下上一篇文章《拥有一个微信机器人总共需要几步?》在这篇文章里,我们提到,创建微信机器人需要一个大前提--你得有一台服务器。现在,不再需要了!没错,上一篇提到的Serverles…...
1、命名空间、C++的复合类型、缺省参数
命名空间 1、命名空间的定义 使用namespace定义,使用作用域限定符::访问 #include <iostream> namespace ICBC{int money 0;void save( int m){money m;} } int main( void ){ICBC::save( 100); std::cout << "工行卡余额:"…...

colab notebook导出为PDF
目录 方法一:使用浏览器打印功能 方法二:使用nbconvert转换 方法三:在线转换 方法一:使用浏览器打印功能 一般快捷键是CTRLP 然后改变目标打印机为另存为PDF 这样就可以将notebook保存为PDF了 方法二:使用nbconver…...

【Python动漫系列】名侦探柯南(完整代码)
文章目录 名侦探柯南环境需求完整代码程序分析系列文章名侦探柯南 《名侦探柯南》是由青山刚昌创作的一部侦探漫画,于1994年开始连载,并被改编为动画、电影、游戏等多种形式。故事讲述了高中生侦探工藤新一在破案时被不良组织所毒害,身体缩小成了一个小学生,为了寻找解药并…...

【matlab】QR分解
QR分解 给定一个mn的矩阵A,其中m≥n,即矩阵A是高矩阵或者是方阵,QR分解将矩阵A分解为两个矩阵Q和R的乘积,其中矩阵Q是一个mn的各列正交的矩阵,即QTQI,矩阵R是一个nn的上三角矩阵,其对角线元素为…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...

【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...

如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...

R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...