装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。 --百度百科
装饰者模式主要是为一个对象增加新的行为,效果与子类扩展父类类似,但实现方式与继承不同,且更加灵活。
Componet: 定义接口基类。
ConcreteComponent: 具体被装饰的目标对象。
Decorator: 装饰类基类。
ConcreteDecoratorA: 具体的装饰类A
ConcreteDecoratorB: 具体的装饰类B
实际需求
实现一款定制日志,包括日志打印增加时间戳、能够打印到终端和文件等功能。
分析
一个最基础的日志功能是将代码调试打印输出至指定文件,现需要在此基础上增加时间戳、终端显示功能。按照以往的写法,直接修改日志功能代码,可能会引起一下问题:
解决方案
引入装饰模式,在原有的日志的接口上封装一层修饰代码。这样就无需修改原先的日志代码,同时保证了新需求的开发。
日志类图
客户端代码
int main(int argc, char *argv[])
{
LOGI("main", "Welcome kaiyuan519!\n");
LOGD("main", "Welcome kaiyuan519!\n");
return 0;
}
终端打印
通过上图可以发现,不仅将客户端打印的字符串输出到同级目录中,同时增加了时间戳、终端显示功能。
代码过长,本篇仅贴主要代码功能。可在公众号后台输入标题获取所有源码。
客户端代码
int main(int argc, char *argv[])
{
LOGI("main", "Welcome kaiyuan519!\n");
LOGD("main", "Welcome kaiyuan519!\n");
return 0;
}
引用修饰类给日志增加新特性
// 定制log:增加时间戳、终端打印
int sys_log(int level, const char *tag, const char *msg)
{
// 保存至文件
if (!pLog) {
pLog = CLog::GetInstance();
}
// 在终端显示
if (!pLog2Terminal) {
pLog2Terminal = CLog2Terminal::GetInstance(pLog);
}
// 增加log调试信息: 时间戳、等级、标签
if (!pLogAddInfo) {
pLogAddInfo = CLogAddInfo::GetInstance(pLog2Terminal);
}
// 完成装饰的接口
pLogAddInfo->SetLogLevel(level);
pLogAddInfo->WriteLog(tag, msg);
return 0;
}
日志增加信息代码
int CLogAddInfo::WriteLog(const char *tag, const char *msg)
{
char logStr[LOG_STR_LENGTH] = {0}; // 一次log打印长度不得超过2000
int length = 0;
// log增加调试信息: time、level、Tag: 2022-01-14 10:09:51.106 I/ <main>
length = get_local_time(logStr);
snprintf(logStr + length, LOG_STR_LENGTH - length, "%s <%s> %s", LEVEL_STR[levelIndex], tag, msg);
CCustomLog::WriteLog(tag, logStr);
return strlen(logStr);
}
输出至终端代码
int CLog2Terminal::WriteLog(const char *tag, const char *msg)
{
// 输出至终端
fprintf(stdout, "%s", msg); // 添加新职能
return CCustomLog::WriteLog(tag, msg);
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。