同步异步日志系统
在我们开发同步异步日志系统之前,需要了解一些相关的技术知识。
一、 不定参函数
在初学C语⾔的时候,我们都⽤过printf函数进⾏打印。其中printf函数就是⼀个不定参函数,在函数内 部可以根据格式化字符串中格式化字符分别获取不同的参数进⾏数据的格式化。
1.1 不定参宏函数的使用
- 首先我们看怎么打印数字和字符。
/*
学习不定参宏函数的使用
*/
#include<stdio.h>
int main()
{
//编译器内置的宏:__FILE__当前文件名;__LINE__当前行号。
printf("[%s:%d],%s %d",__FILE__,__LINE__,"你好世界",521);
return 0;
}
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. 单一职责原则(SingleResponsibilityPrinciple )
- 类的职责应该单⼀,⼀个⽅法只做⼀件事。
- 使⽤建议:两个完全不⼀样的功能不应该放⼀个类中,⼀个类中应该是⼀组相关性很⾼的函数或数据的封装。
- 例子:⽹络聊天:⽹络通信&聊天,应该分割成为⽹络通信类&聊天类。
- 对扩展开放,对修改封闭。
- 使⽤建议:对软件实体的改动,最好⽤扩展⽽⾮修改的⽅式。
- ⽤例:超时卖货:商品价格—不是修改商品的原来价格,⽽是新增促销价格。
- 通俗点讲,就是只要⽗类能出现的地⽅,⼦类就可以出现,⽽且替换为⼦类也不会产⽣任何错误或异常。
- 在继承类时,务必重写⽗类中所有的⽅法,尤其需要注意⽗类的protected⽅法,⼦类尽量不要暴露⾃⼰的public⽅法供外界调⽤。
- 使⽤建议:⼦类必须完全实现⽗类的⽅法,孩⼦类可以有⾃⼰的个性。覆盖或实现⽗类的⽅法时,输⼊参数可以被放⼤,输出可以缩⼩。
- ⽤例:跑步运动员类-会跑步,⼦类⻓跑运动员-会跑步且擅⻓⻓跑,⼦类短跑运动员-会跑步且擅⻓短跑。
- ⾼层模块不应该依赖低层模块,两者都应该依赖其抽象.不可分割的原⼦逻辑就是低层模式,原⼦逻辑组装成的就是⾼层模块。
- 模块间依赖通过抽象(接⼝)发⽣,具体类之间不直接依赖。
- 使⽤建议:每个类都尽量有抽象类,任何类都不应该从具体类派⽣。尽量不要重写基类的⽅法。结合⾥⽒替换原则使⽤。
- ⽤例