[C++]——同步异步日志系统(2)

C++ LinuxWebServer项目(5)同步异步日志系统 同步异步日志系统解决并发量问题 阅读详情

在我们开发同步异步日志系统之前,需要了解一些相关的技术知识。

一、 不定参函数

在初学C语⾔的时候,我们都⽤过printf函数进⾏打印。其中printf函数就是⼀个不定参函数,在函数内 部可以根据格式化字符串中格式化字符分别获取不同的参数进⾏数据的格式化。

1.1 不定参宏函数的使用

  1. 首先我们看怎么打印数字和字符。
/*
学习不定参宏函数的使用
*/
#include<stdio.h>
int main()
{
//编译器内置的宏:__FILE__当前文件名;__LINE__当前行号。
printf("[%s:%d],%s %d",__FILE__,__LINE__,"你好世界",521);
    return 0;
}   

在这里插入图片描述
2. 用宏表示不定参数

  1. 不定参的表示用:“…”
  2. 不定参的使用:“ __ VA_REGS __”。(如果 __ VA_REGS __是空的话就在前面加 ## ,这里的作用就是取消前面的逗号。)
#include<stdio.h>
#define LOG(fmt,...) printf("[%s:%d]", __FILE__, __LINE__, __VA_ARGS__);
int main()
{
//编译器内置的宏:__FILE__当前文件名;__LINE__当前行号。
    LOG("%s %d\n","你好世界",521)
    return 0;
}   

在这里插入图片描述
3. 如果只有LOG(“你好世界”),就会报错;这时候就要加##号。
在这里插入图片描述

#include<stdio.h>
#define LOG(fmt,...) printf("[%s:%d]", __FILE__, __LINE__,##__VA_ARGS__);
int main()
{
//编译器内置的宏:__FILE__当前文件名;__LINE__当前行号。
    LOG("你好世界")
    return 0;
} 

在这里插入图片描述

1.2 C 语言中不定参函数的使用

/*
C语言中不定参函数的使用,不定参数据的访问
*/
#define _GNU_SOURCE//使用vasprintf函数必须带这个宏
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
//参数类型一样
void printNum(int n, ...)
{
    va_list al;//可变参数
    va_start(al, n); //  获取指定参数的起始地址,这里就是获取n参数之后的第一个参数的起始地址
    for (int i = 0; i < n; i++)
    {
        int num = va_arg(al, int); // 从可变参数中取出⼀个整形参数
        printf("param[%d]:%d\n", i, num);
    }
    va_end(al); // 清空可变参数列表--其实是将al置空
}
//参数类型不一样
void myprintf(const char*fmt,...)
{
    va_list ap;
    va_start(ap,fmt);
    char *res;
    //对不定参数的基本使用;給一个一级指针的地址进去,根据fmt里面的字符串格式,一个一个的取出参数列表的每个数。
    int ret=vasprintf(&res,fmt,ap);
    if(ret!=-1)
    {
        printf(res);
        free(res);
    }
    va_end(ap);//将ap指针置空
}
int main()
{
    printNum(3, 11, 22,33);
    printNum(5, 44, 55, 66, 77, 88);
    myprintf("%s %d","hello",521);
    return 0;
}

在这里插入图片描述

1.3 C++不定参数使用

#include <iostream>

//特化
void xprintf()
{
    std::cout<<std::endl;
}

template <typename T,typename ...Args>
void xprintf(const T &v,Args &&...args)
{
    std::cout<<v;
    //sizeof计算参数包参数的个数
    if((sizeof ...(args))>0)
    {
        //完美转发
        xprintf(std::forward<Args>(args)...);
    }
    else{
        //递归为0的情况 
        xprintf();
    }
}

int main()
{
xprintf("hello!","world",521);
xprintf("hello!","world");
xprintf("hello!");
    return 0;
}

在这里插入图片描述

二、设计模式

设计模式是前辈们对代码开发经验的总结,是解决特定问题的⼀系列套路。它不是语法规定,⽽是⼀ 套⽤来提⾼代码可复⽤性、可维护性、可读性、稳健性以及安全性的解决⽅案。

六大原则:

  1. 1. 单一职责原则(SingleResponsibilityPrinciple )
    • 类的职责应该单⼀,⼀个⽅法只做⼀件事。
    • 使⽤建议:两个完全不⼀样的功能不应该放⼀个类中,⼀个类中应该是⼀组相关性很⾼的函数或数据的封装。
    • 例子:⽹络聊天:⽹络通信&聊天,应该分割成为⽹络通信类&聊天类。
    2. 开闭原则(OpenClosedPrinciple )
    • 对扩展开放,对修改封闭。
    • 使⽤建议:对软件实体的改动,最好⽤扩展⽽⾮修改的⽅式。
    • ⽤例:超时卖货:商品价格—不是修改商品的原来价格,⽽是新增促销价格。
    3. 里氏替换原则(LiskovSubstitutionPrinciple )
    • 通俗点讲,就是只要⽗类能出现的地⽅,⼦类就可以出现,⽽且替换为⼦类也不会产⽣任何错误或异常。
    • 在继承类时,务必重写⽗类中所有的⽅法,尤其需要注意⽗类的protected⽅法,⼦类尽量不要暴露⾃⼰的public⽅法供外界调⽤。
    • 使⽤建议:⼦类必须完全实现⽗类的⽅法,孩⼦类可以有⾃⼰的个性。覆盖或实现⽗类的⽅法时,输⼊参数可以被放⼤,输出可以缩⼩。
    • ⽤例:跑步运动员类-会跑步,⼦类⻓跑运动员-会跑步且擅⻓⻓跑,⼦类短跑运动员-会跑步且擅⻓短跑。
    4. 依赖倒置原则(Dependence Inversion Principle)
    • ⾼层模块不应该依赖低层模块,两者都应该依赖其抽象.不可分割的原⼦逻辑就是低层模式,原⼦逻辑组装成的就是⾼层模块。
    • 模块间依赖通过抽象(接⼝)发⽣,具体类之间不直接依赖。
    • 使⽤建议:每个类都尽量有抽象类,任何类都不应该从具体类派⽣。尽量不要重写基类的⽅法。结合⾥⽒替换原则使⽤。
    • ⽤例:奔驰⻋司机类–只能开奔驰;司机类–给什么⻋,就开什么⻋;开⻋的⼈:司机–依赖于抽象。
    5. 迪⽶特法则(LawofDemeter),⼜叫“最少知道法则”
    • 尽量减少对象之间的交互,从⽽减⼩类之间的耦合。⼀个对象应该对其他对象有最少的了解。 对类的低耦合提出了明确要求:1.只和直接的朋友交流,朋友之间也是有距离的。⾃⼰的就是⾃⼰的。(如果⼀个⽅法放在本类中,既不增加类间关系,也对本类不产⽣负⾯影响,那就放置在本类中)
    • ⽤例:⽼师让班⻓点名–⽼师给班⻓⼀个名单,班⻓完成点名勾选,返回结果,⽽不是班⻓点名,⽼师勾选。
    6. 接⼝隔离原则(Interface Segregation Principle );
    • 客⼾端不应该依赖它不需要的接⼝,类间的依赖关系应该建⽴在最⼩的接⼝上。
    • 使⽤建议:接⼝设计尽量精简单⼀,但是不要对外暴露没有实际意义的接⼝。
    • ⽤例:修改密码,不应该提供修改⽤⼾信息接⼝,⽽就是单⼀的最⼩修改密码接⼝,更不要暴露数据库操作。

从整体上来理解六⼤设计原则,可以简要的概括为⼀句话,⽤抽象构建框架,⽤实现扩展细节,具体到每⼀条设计原则 则对应⼀条注意事项:

  1. 单⼀职责原则告诉我们实现类要职责单⼀;
  2. 开闭原则是总纲,告诉我们要对扩展开放,对修改关闭;
  3. ⾥⽒替换原则告诉我们不要破坏继承体系;
  4. 依赖倒置原则告诉我们要⾯向接⼝编程;
  5. 迪⽶特法则告诉我们要降低耦合;
  6. 接⼝隔离原则告诉我们在设计接⼝的时候要精简单⼀。

2.1 单列模式

一个类只创建一个对象。 该设计模式可以保证系统中该类只有⼀个实例化对象,并提供⼀个访问它的全局访问点,该实例被所有程序模块共享。⽐如在某个服务器程序中,该服务器的配置信息存放在⼀个⽂件中,这些配置数据由⼀个单例对象统⼀读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种⽅式简化了在复杂环境下的配置管理。

  1. 饿汉模式

程序启动时就会创建⼀个唯⼀的实例对象。因为单例对象已经确定,所以⽐较适⽤于多线程环境中,多线程获取单例对象不需要加锁,可以有效的避免资源竞争,提⾼性能。

#include <iostream>
// 饿汉模式的单例模式
class Singleton
{
private:
    static Singleton _eton; // 实例化一个对象,这个是声明,需要在类外面定义
    Singleton() : _data(99)
    {
        std::cout << "单例对象构造\n";
        ;
    }; // 初始化列表
    Singleton(const Singleton &) = delete; // 禁止拷贝构造
    ~Singleton(){};                        // 析构函数
private:
    int _data; // 日期
public:
    // 给类外调用的接口,获得类的信息。
    static Singleton &getInstance()
    {
        return _eton;
    }
    int getData()
    {
        return _data;
    }
};
Singleton Singleton::_eton;

int main()
{
    std::cout << Singleton::getInstance().getData(); // 获得实例化后对象的信息;
    return 0;
}

在这里插入图片描述
2. 懒汉模式

懒加载,延迟加载的思想,一个对象在用的时候在进行实例化。 如果单例对象构造特别耗时或者耗费济 源(加载插件、加载⽹络资源等), 可以选择懒汉模式, 在第⼀次使⽤的时候才创建对象。

  • 这⾥介绍的是《Effective C++》⼀书作者ScottMeyers 提出的⼀种更加优雅简便的单例模式 Meyers’Singleton in C++。
  • C++11 Static local variables特性以确保C++11起,静态变量将能够在满⾜ thread-safe 的前提 下唯⼀地被构造和析构
#include <iostream>
// 懒汉模式的单例模式:定义对象的时候不是直接实例化对象
class Singleton
{
private:
    Singleton() : _data(99)
    {
        std::cout << "单例对象构造\n";
        ;
    }; // 初始化列表
    Singleton(const Singleton &) = delete; // 禁止拷贝构造
    ~Singleton(){};                        // 析构函数
private:
    int _data; // 日期
public:
    // 给类外调用的接口,获得类的信息。
    static Singleton &getInstance()
    {
        static Singleton _eton; // c++11之后才开始这么做,c++11之前都是先定义一个对象指针,如果是空就不实例化对象,不是空就new对象,存在线程安全的问题,要加锁
        return _eton;
    }
    int getData()
    {
        return _data;
    }
};
int main()
{
    std::cout << Singleton::getInstance().getData(); // 获得实例化后对象的信息;
    return 0;
}

在这里插入图片描述

2.2 工厂模式

⼯⼚模式是⼀种创建型设计模式,它提供了⼀种创建对象的最佳⽅式。在⼯⼚模式中,我们创建对象时不会对上层暴露创建逻辑,⽽是通过使⽤⼀个共同结构来指向新创建的对象,以此实现创建-使⽤的分离。

⼯⼚模式可以分为:

  1. 简单工厂模式

简单⼯⼚模式实现由⼀个⼯⼚对象通过类型决定创建出来指定产品类的实例。假设有个⼯⼚能⽣产出⽔果,当客⼾需要产品的时候明确告知⼯⼚⽣产哪类⽔果,⼯⼚需要接收⽤⼾提供的类别信息,当新增产品的时候,⼯⼚内部去添加新产品的⽣产⽅式。

//简单⼯⼚模式:通过参数控制可以⽣产任何产品
// 优点:简单粗暴,直观易懂。使⽤⼀个⼯⼚⽣产同⼀等级结构下的任意产品
// 缺点:
// 1. 所有东西⽣产在⼀起,产品太多会导致代码量庞⼤
//2. 开闭原则遵循(开放拓展,关闭修改)的不是太好,要新增产品就必须修改⼯⼚⽅法。
#include <iostream>
#include <memory>
// 简单工厂模式
// 水果类
class Fruits
{
public:
    Fruits(){}; // 构造函数
    // 创建生产方式的纯虚函数
    virtual void show() = 0;
};
// 水果的产品
class Apple : public Fruits
{
public:
    Apple(){};
    virtual void show()
    {
        std::cout << "我是一个红苹果" << std::endl;
    };
};
class Banana : public Fruits
{
public:
    Banana(){};
    virtual void show()
    {
        std::cout << "我是一个黄香蕉" << std::endl;
    };
};

// 给我们使用的水果工厂
class FritisFactory
{
public:
    // 创建水果的方法
    static std::shared_ptr<Fruits> create(const std::string &name)
    {
        if (name == "苹果")
            return std::make_shared<Apple>();
        else
            return std::make_shared<Banana>();
    }
};

int
main()
{
    std::shared_ptr<Fruits> fruit = FritisFactory::create("苹果"); // 工厂生产苹果
    fruit->show();                                                 // 显示苹果
    fruit = FritisFactory::create("香蕉");                         // 工厂生产香蕉
    fruit->show();                                                 // 显示香蕉
    return 0;
}

在这里插入图片描述
这个模式的结构和管理产品对象的⽅式⼗分简单, 但是它的扩展性⾮常差,当我们需要新增产品的时 候,就需要去修改⼯⼚类新增⼀个类型的产品创建逻辑,违背了开闭原则。

  1. 工厂方法模式

在简单⼯⼚模式下新增多个⼯⼚,多个产品,每个产品对应⼀个⼯⼚。假设现在有 A、B 两种产品,则开两个⼯⼚,⼯⼚ A 负责⽣产产品 A,⼯⼚ B 负责⽣产产品 B,用户只知道产品 的⼯⼚名,⽽不知道具体的产品信息,⼯⼚不需要再接收客户的产品类别,⽽只负责⽣产产品。

//⼯⼚⽅法:定义⼀个创建对象的接⼝,但是由⼦类来决定创建哪种对象,使⽤多个⼯⼚分别⽣产指定 的固定产品
// 优点: 
// 1. 减轻了⼯⼚类的负担,将某类产品的⽣产交给指定的⼯⼚来进⾏
// 2. 开闭原则遵循较好,添加新产品只需要新增产品的⼯⼚即可,不需要修改原先的⼯⼚类
// 缺点:对于某种可以形成⼀组产品族的情况处理较为复杂,需要创建⼤量的⼯⼚类.
#include <iostream>
#include <memory>
// 工厂方法模式
// 水果类
class Fruits
{
public:
    Fruits(){}; // 构造函数
    // 创建生产方式的纯虚函数
    virtual void show() = 0;
};
// 水果的产品
class Apple : public Fruits
{
public:
    Apple(){};
    virtual void show()
    {
        std::cout << "我是一个红苹果" << std::endl;
    };
};
class Banana : public Fruits
{
public:
    Banana(){};
    virtual void show()
    {
        std::cout << "我是一个黄香蕉" << std::endl;
    };
};

// 给我们使用的水果工厂
class FritisFactory
{
public:
    // 创建水果的纯虚函数
    virtual std::shared_ptr<Fruits> create() = 0;
};

// 苹果工厂
class AppleFactory
{
public:
    std::shared_ptr<Fruits> create() override // 用来重写基类的同名虚函数
    {
        return std::make_ptr<Apple>();
    }
};
// 香蕉工厂
class BananFactory
{
public:
    std::shared_ptr<Fruits> create() override // 用来重写基类的同名虚函数
    {
        return std::make_ptr<Banana>();
    }
};

int main()
{
    std::shared_ptr<FritisFactory> ff(new AppleFactory()); // 创建一个苹果工厂
    std::shared_ptr<Fruits> fruit = ff->create();          // 生产苹果
    fruit->show();
    ff.reset(new BananFactory()); // 重新管理工厂为香蕉工厂
    fruit = ff->create();         // 创建一个香蕉
    fruit->show();                // 生产香蕉
    return 0;
}

在这里插入图片描述
⼯⼚⽅法模式每次增加⼀个产品时,都需要增加⼀个具体产品类和⼯⼚类,这会使得系统中类的个数 成倍增加,在⼀定程度上增加了系统的耦合度。

  1. 抽象工厂模式

⼯⼚⽅法模式通过引⼊⼯⼚等级结构,解决了简单⼯⼚模式中⼯⼚类职责太重的问 题,但由于⼯⼚⽅法模式中的每个⼯⼚只⽣产⼀类产品,可能会导致系统中存在⼤量的⼯⼚类,势必会增加系统的开销。此时,我们可以考虑将⼀些相关的产品组成⼀个产品族(位于不同产品等级 结构中功能相关联的产品组成的家族),由同⼀个⼯⼚来统⼀⽣产,这就是抽象⼯⼚模式的基本思想。

//抽象⼯⼚:围绕⼀个超级⼯⼚创建其他⼯⼚。每个⽣成的⼯⼚按照⼯⼚模式提供对象。
// 思想:将⼯⼚抽象成两层,抽象⼯⼚ & 具体⼯⼚⼦类, 在⼯⼚⼦类种⽣产不同类型的⼦产品
#include <iostream>
#include <memory>
// 抽象工厂模式
// 水果类
class Fruits
{
public:
    Fruits(){}; // 构造函数
    // 创建生产方式的纯虚函数
    virtual void show() = 0;
};
// 水果的产品
class Apple : public Fruits
{
public:
    Apple(){};
    virtual void show()
    {
        std::cout << "我是一个红苹果" << std::endl;
    };
};
class Banana : public Fruits
{
public:
    Banana(){};
    virtual void show()
    {
        std::cout << "我是一个黄香蕉" << std::endl;
    };
};

// 动物类
class Animal
{
public:
    Animal(){}; // 构造函数
    // 创建生产方式的纯虚函数
    virtual void name1() = 0;
};
// 动物的产品
class Lamp : public Animal
{
public:
    Lamp(){};
    virtual void name1()
    {
        std::cout << "我是一只山羊" << std::endl;
    };
};
class Dog : public Animal
{
public:
    Dog(){};
    virtual void name1()
    {
        std::cout << "我是一只狗" << std::endl;
    };
};

// 给我们使用的抽象工厂
class Factory
{
public:
    // 创建分类的纯虚函数
    virtual std::shared_ptr<Fruits> getFruits(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<Fruits> getFruits(const std::string &name)
    {
        if (name == "苹果")
            return std::make_shared<Apple>();
        else if (name == "香蕉")
            return std::make_shared<Banana>();
        else
            return std::shared_ptr<Fruits>(); // 否则为空
    }
};
// 动物工厂
class AnimalFactory : public Factory
{
public:
    virtual std::shared_ptr<Fruits> getFruits(const std::string &name)
    {
        return std::shared_ptr<Fruits>(); // 返回一个空对象
    }
    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>();
        else
            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<Fruits> fruit = fruit_factory->getFruits("苹果");
    fruit->show();
    fruit = fruit_factory->getFruits("香蕉");
    if (fruit == nullptr)
    {
        return 0;
    }
    fruit->show();
    std::shared_ptr<Factory> animal_factory = FactoryProducer::getFactory("动物");
    std::shared_ptr<Animal> animal = animal_factory->getAnimal("小羊");
    animal->name1();
    animal = animal_factory->getAnimal("小狗");
    if (animal == nullptr)
    {
        return 0;
    }
    animal->name1();
    return 0;
}

在这里插入图片描述
抽象⼯⼚模式适⽤于⽣产多个⼯⼚系列产品衍⽣的设计模式,增加新的产品等级结构复杂,需要对原 有系统进⾏较⼤的修改,甚⾄需要修改抽象层代码,违背了“开闭原则”。

2.3 建造者模式

建造者模式是⼀种创建型设计模式, 使⽤多个简单的对象⼀步⼀步构建成⼀个复杂的对象(可能会按照一定的顺序才能构建成产品),能够将⼀个复杂的对象的构建与它的表⽰分离,提供⼀种创建对象的最佳⽅式。主要⽤于解决对象的构建过于 复杂的问题。

建造者模式主要基于四个核⼼类实现:

  • 抽象产品类:
  • Product(产品角色):⼀个具体的产品对象类
  • Builder(抽象建造者):创建⼀个产品对象所需的各个部件的抽象接⼝
  • ConcreteBuilder(具体建造者):实现抽象接⼝,构建各个部件
  • Director类(指挥者):统⼀组建过程,提供给调⽤者使⽤,通过指挥者来构造产品。
#include <iostream>
#include <memory>
#include <string>
// 建造者模式
// 1.先创建产品的抽象类
class Computer
{
public:
    // 构建零部件的方法
    void setBoard(const std::string &board)
    {
        _board = board;
    }
    void setDisply(const std::string &display)
    {
        _display = display;
    }
    virtual void setOs() = 0;
    std::string toString()
    {
        std::string computer = "Computer:{\n";
        computer += "\tboard=" + _board + ",\n";
        computer += "\tdisplay=" + _display + ",\n";
        computer += "\tOs=" + _os + ",\n";
        computer += "}\n";
        return computer;
    }

protected: // 如果是私有的零部件,
    // 这是我们构造电脑所需要的零部件。
    std::string _board;   // 主板
    std::string _display; // 显示屏
    std::string _os;      // 操作系统
};

// 2.对产品抽象接口的具体实现
class MacBook : public Computer
{
public:
    // 构建抽象零部件的方法
    void setOs() override
    {
        _os = "Mac os x12";
    }
};

// 3.完成各个零部件的生产过程
class Builder
{
public:
    virtual void builBoard(const std::string &board) = 0;
    virtual void builDisplay(const std::string &display) = 0;
    virtual void builOs() = 0;
    virtual std::shared_ptr<Computer> build() = 0;
};

// 4.实现抽象接⼝,构建各个部件
class MacBookBuild : public Builder
{
public:
    MacBookBuild() : _computer(new MacBook()) {}
    void builBoard(const std::string &board)
    {
        _computer->setBoard(board);
    }
    void builDisplay(const std::string &display)
    {
        _computer->setDisply(display);
    }
    void builOs()
    {
        _computer->setOs();
    }
    std::shared_ptr<Computer> build()
    {
        return _computer;
    }
    std::shared_ptr<Computer> _computer;
};

// 指挥者
class Director
{
public:
    Director(Builder *builder) : _builder(builder) {}
    void construct(const std::string &board, const std::string &display)
    {
        _builder->builBoard(board);
        _builder->builDisplay(display);
        _builder->builOs();
    }

private:
    std::shared_ptr<Builder> _builder;
};

int main()
{
    Builder *builder = new MacBookBuild();                     // 苹果系统的建造者构造
    std::unique_ptr<Director> director(new Director(builder)); // 指挥者准备好了
    director->construct("华硕主板", "三星显示器");             // 组装好了
    std::shared_ptr<Computer> computer = builder->build();     //
    std::cout << computer->toString();
    return 0;
}

在这里插入图片描述

2.4 代理模式

代理模式指代理控制对其他对象的访问, 也就是代理对象控制对原对象的引⽤。在某些情况下,⼀个对象不适合或者不能直接被引⽤访问,⽽代理对象可以在客⼾端和⽬标对象之间起到中介的作⽤。代理模式的结构包括⼀个是真正的你要访问的对象(⽬标类)、⼀个是代理对象。⽬标对象与代理对象实现同⼀个接⼝,先访问代理类再通过代理类访问⽬标对象。

代理模式分为静态代理、动态代理:

  • 静态代理指的是,在编译时就已经确定好了代理类和被代理类的关系。也就是说,在编译时就已经 确定了代理类要代理的是哪个被代理类。
  • 动态代理指的是,在运⾏时才动态⽣成代理类,并将其与被代理类绑定。这意味着,在运⾏时才能 确定代理类要代理的是哪个被代理类。

以租房为例,房东将房⼦租出去,但是要租房⼦出去,需要发布招租启⽰, 带⼈看房,负责维修,这 些⼯作中有些操作并⾮房东能完成,因此房东为了图省事,将房⼦委托给中介进⾏租赁。
代理模式实现:

// 房东要把一个房子通过中介租出去
#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;
}

在这里插入图片描述

基于log4j的java异步Log的打印实现 使用消费者-生产者模式为主要指导思想设计的多线程log打印的一个通用模块类。基于log4j,但是不需要进行特别配置,不需要单独写配置文件,自带配置文件。仅需要简单的修改即可实现smtp远程log模式。 经测验,1000条Log同时打印的效率比仅仅使用log4j的时候高6-10倍。(呵呵,多线程嘛) 有什么要求、体会,请与我联系! http://qianxuechao.blog.163.com/ 立即下载

相关推荐

log4j2日志异步打印(实例讲解)

下面小编就为大家带来一篇log4j2日志异步打印(实例讲解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

Logback日志异步打印接入指南,输出自定义业务数据

随着应用的请求量上升,日志输出量也会成线性比例的上升,给磁盘IO带来压力与性能瓶颈。应用也遇到了线程池满,是因为大量线程卡在输出日志。为了缓解日志同步打印,会采取异步打印日志。这样会引起日志中的追踪id丢失,不能基于追踪id查询相关日志,给问题解决带来新的挑战。 使用MdcUtil传递用户id、教练id、优惠券id、商品id、交易订单id、支付订单id、物流订单id、api、responseTime、responseCode、追踪id等,从用户、教练、营销、商品、交易、物流等维度观测用户的实操路径。

简放视野的专栏 1741

携程景点评论数据爬取实战:破解AJAX动态加载与分页参数逆向分析

本文详细介绍了携程景点评论数据爬取的实战经验,重点破解了AJAX动态加载与分页参数逆向分析的技术难题。通过分析`getCommentCollapseList`接口,解析动态参数如`poiId`和`pageIndex`,并实现分页逻辑,帮助开发者高效获取评论数据。文章还提供了完整的Python爬虫代码和反爬策略,适用于数据分析与内容挖掘。

weixin_29098367的博客 673

使用logback异步打印日志

对于每一个开发人员来说,在业务代码中添加日志是至关重要的,尤其是后端开发,如果不打印日志,在接口出现bug的时候将无法定位bug;有了日志,即使接口出现bug,也可以通过查询日志很快的定位到bug的位置。使用springboot开发的朋友使用最多的日志框架想必都是logback了吧,毕竟它是springboot官方推荐的日志框架,与springboot天然整合。再结合第三方工具lombok,当我们需要打印日志时只需要通过log.info("第一条日志");

理想万岁万万岁的博客 6174

智慧楼宇解决方案-全套大合集

智慧楼宇解决方案,楼宇能耗-环境-设备统一管控解决方案。

byte58的博客 2590

巨某量引擎后台登录实战笔记 | Playwright自动化框架

自动化框架、Playwright、滑块、巨某量引擎、抖某音系

什么都会一点。 2076

Java优化(三) 日志打印

日志记录是应用程序运行中必不可少的一部分。具有良好格式和完备信息的日志记录可以在程序出现问题时帮助开发人员迅速地定位错误的根源。对于开 发人员来说,在程序中使用日志API记录日志并不复杂,不过遵循一些最佳实践可以更好的利用日志

dmjxsy的博客 4387

〖Python网络爬虫实战㊴〗- 极验滑块介绍(一)

我们对这个看到不陌生,现在,大多数平台都是用的是这个平台的验证码,我们今天来学习一下,极验滑块验证码的逆向,其他的都差不多。我们了解到这个平台提供了许多验证的方式。现在大多数还是滑块比较多,滑块验证码是一种常见的验证方式,其主要思路为用户通过拖动滑块来完成验证。具体流程如下:首先,用户需要进行滑块验证码的操作,网站会向用户展示一张图片,图片上通常会有一些随机的文字和背景干扰。用户需要通过鼠标拖动滑块,将其移动到指定位置上,通常是将滑块拖动到图片的相应位置上来完成验证。

爱吃饼干的小白鼠的博客 2878

【c++】异步打印服务日志

c++ 异步打印服务日志

瑾修的博客 572

AI赋能合同审查:构建租赁合同智能审核系统的全流程解析

在商业地产、设备租赁等场景中,合同审核效率直接影响业务流转速度。传统人工审核存在三大痛点:审核周期长(平均2-3个工作日)、合规风险高(条款遗漏率约15%)、人力成本居高不下。智能审核系统可将审核时间压缩至秒级,风险识别准确率提升至98%以上。

理论都是虚的,代码才是王道。 1354

Python 爬虫实战:全球渔业船舶捕捞记录数据采集与分析全攻略

通过本项目,我们实现了对全球渔业船舶捕捞记录数据的采集、处理和可视化,为渔业资源管理和海洋生态保护提供了数据支持。未来,可以进一步结合机器学习和深度学习技术,对捕捞行为进行预测和分类,提高对非法捕捞活动的识别能力。

2201_76125261的博客 554

高并发高性能接口中,异步打印并采集业务日志的实现方案

本文试着通过另外一个解决方案来保证高并发接口的高性能,顺便介绍了如何找回filebeat所在机器的过程。同时提醒我们,在采集数据的时候,或者程序开发的时候,特别是当你的链路很长的时候,把每个环节的主体信息记录下来是多么的重要。

天草二十六 1729

Arduino、ESP32驱动SFA40甲醛传感器(气体传感器篇)

SFA40甲醛传感器是一款基于盛思锐电化学原理的专业HCHO检测模块,具备卓越的抗酒精干扰能力(乙醇交叉敏感度<0.3%)、高达±20ppb的检测精度及0~1000ppb的宽量程。该传感器内置SHT4X温湿度传感器进行自动补偿,确保数据的长期稳定性;其小尺寸、低功耗的特性,可快速集成至智能家居、空气净化器、物联网环境监测等系统中,实现对甲醛浓度的精准、可靠监测。

不脱发的程序猿 301

C++基于多设计模式下的同步&异步日志系统day2

主要内容实现了日志代码设计的实用类设计,日志等级设计,日志消息类设计。

本科在读,致力于Linux/C++方向的学习,同时涉及数据结构与算法,操作系统,数据库mysql等等 1512

第4章 部署负载均衡 Keepalived + HAProxy

本章在所有 Master 节点部署 Keepalived + HAProxy,为 kube-apiserver 提供高可用入口。Keepalived 实现 VIP(192.168.3.59)漂移,HAProxy 轮询转发请求至三个 Master 的 6443 端口(监听 6444 避免冲突)。健康检查脚本连续 5 次失败则停止 Keepalived,触发 VIP 自动切换。本章还包含配置详解、日常运维和问题排查。

幸福街--linux技术分享 120

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

C++项目 —— 基于多设计模式下的同步&异步日志系统(2)(工厂模式)

C++项目 —— 基于多设计模式下的同步&异步日志系统(2)(工厂模式)

qq_67693066的博客 1299

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

同步&异步日志系统:前置知识

日志:程序运行过程中所记录的程序运行状态(时间、错误原因、行号……) 作用:记录了程序运行状态信息,以便于程序员能够随时根据状态信息对系统的运行状态进行分析 一般来说日志都是作为一个小组件给其他业务打辅助用的,所以我们为了确保他能够更高效地开发,除了他能够正常使用之外,必要时候也要去阐述他的具体性能!!

weixin_51142926的博客 1554

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

C++- 基于多设计模式下的同步&异步日志系统

13万字项目带源代码

ljw的博客 2494

C++ - 基于多设计模式下的同步&异步日志系统(11w字)

支持多级别日志消息支持同步日志和异步日志支持可靠写入日志到控制台、文件以及滚动文件中支持多线程程序并发写文件支持拓展不同的日志落地目标地⽣产环境的产品为了保证其稳定性及安全性是不允许开发⼈员附加调试器去排查问题, 可以借助⽇志系统来打印⼀些⽇志帮助开发⼈员解决问题上线客⼾端的产品出现bug⽆法复现并解决, 可以借助⽇志系统打印⽇志并上传到服务端帮助开发⼈员进⾏分析。

2301_80863610的博客 1万+

同步+异步日志系统(C++实现)

对于一个服务器而言,不论是在调试中还是在运行中,都需要通过打日志的方式来记录程序的运行情况。日志写入函数与工作线程串行执行,由于涉及到I/O操作,当单条日志比较大的时候,同步模式会阻塞整个处理流程,服务器所能处理的并发能力将有所下降,尤其是在峰值的时候,写日志可能成为系统的瓶颈。将所写的日志内容先存入中,写线程从阻塞队列中取出内容,写入日志。

weixin_50437588的博客 6284

C++日志系统:高效异步日志实现解析

本文介绍了一个功能完善的多日志器日志系统,支持同步/异步日志输出,具备以下核心特性: 系统架构 采用模块化设计,包含日志等级、消息格式化、落地处理和日志器等模块 支持同步日志(直接写入)和异步日志(双缓冲队列) 提供多种日志落地方式:控制台、文件和滚动文件 关键技术 基于C++11实现线程安全日志记录 采用生产者-消费者模型处理异步日志 运用多种设计模式:单例、工厂、建造者和代理模式 实现可变参数日志接口,支持printf风格格式化 核心功能 多级别日志输出(DEBUG/INFO/WARN/ERROR/FA

2401_86275172的博客 2541

【项目】C++ 基于多设计模式下的同步&异步日志系统

前言 一般而言,业务的服务都是周而复始的运行,当程序出现某些问题时,程序员要能够进行快速的修复,而修复的前提是要能够先定位问题。 因此为了能够更快的定位问题,我们可以在程序运行过程中记录一些日志,通过这些日志我们便能够很容易地了解程序的运行状态,以及程序崩溃时的一些信息,有了这些信息我们便能够更好的定位问题以及分析问题了。 本项目代码地址:日志系统 C++ 基于多设计模式下的同步&异步日志系统前言日志系统的必要性项目相关介绍1、功能2、开发环境和工具3、核心技术4、环境搭建日志系统技

一点一点变好 2329

【C++基于多设计模式下的同步&异步日志系统】

从0到1教你学会第一个容易上手的C++项目

m0_68872612的博客 2183

[C++]——同步异步日志系统(6)

异步的思想就是不让业务线程进行日志的实际落地,而是将日志消息放到缓冲区(一块指定的内存)中接下来有一个专门的异步线程,去针对缓冲区中的数据进行处理(实际的落地操作)因此:日志器类在设计的时候,先要设计一个Logger的基类,在Logger基类的基础上,继承出同步日志器(SyncLogger)和异步日志器(AsyncLoggrr)。

plj521的博客 2373

【C++项目实战】基于多设计模式下的同步于异步的日志系统(完整详细)

基于多设计模式下的同步与异步日志系统

VHhhbb的博客 1995

C++基于多设计模式下的同步&异步日志系统day1

主要内容记录了,日志项目需要的一些前置的补充知识。

本科在读,致力于Linux/C++方向的学习,同时涉及数据结构与算法,操作系统,数据库mysql等等 1656
上一篇: [C++]——同步异步日志系统(1)
下一篇: VSCode远程连接Linux服务器
一个小脑袋
一个小脑袋 新星创作者: C/C++技术领域 新星创作者: C/C++技术领域
博客等级 码龄6年 4388粉丝 79原创
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值