C++项目 ------ 基于多设计模式下的同步&异步日志系统(5)(建造者模式)
我们上次已经把日志器模块的主要的两大块已经编写的差不多了------同步日志器和异步日志器。如果有小伙伴对此还不太熟悉可以点击这里:
https://blog.csdn.net/qq_67693066/article/details/147350462?spm=1011.2415.3001.5331
我们今天的题目建造者模式,是为了解决我们在简单测试的时候的一个问题:
一个问题
我们之前测试的时候,如果我们要构建一个日志器非常麻烦:
cpp
logs::Formetter formatter("abc[%d{%H:%M:%S}][%c]%T%m%n");
logs::Formetter::ptr fmt_ptr = std::make_shared<logs::Formetter>(formatter);
auto st1 = logs::SinkFactory::create<logs::StdoutSink>();
std::vector<logs::BaseSink::ptr> sinks = {st1};
std::string logger_name = "asynclogger";
logs::BaseLogger::ptr logger(new logs::AsyncLogger(logger_name, logs::Loglevel::value::DEBUG, fmt_ptr, sinks,logs::AsyncLooper::AsyncType::ASYNC_SAFE));
logger->debug("main.cc", 53, "%s","格式化功能测试....");
构造一个日志器,我们就要用八九行代码,而且这是在我们很熟悉日志器结构的基础上我们才能写出来这样的代码,对于不熟悉代码结构的人,恐怕无法写出完整的代码来构建日志器。
因为日志器对象的构建过于复杂,所以我们就有了建造者模式的概念,大家可以点击以下连接来进行查看关于建造者模式的一些相关知识:
https://blog.csdn.net/qq_67693066/article/details/145543280?spm=1011.2415.3001.5331
建造者模式(Builder Pattern)
建造者模式是一种创建型设计模式,它允许逐步构建复杂的对象。这种模式对于需要构造具有许多可选组件的对象特别有用。通过使用建造者模式,可以避免构造函数参数列表过长的问题,并且使得代码更加清晰和易于维护。
主要概念
- 产品角色(Product):最终需要创建的复杂对象。
- 抽象建造者(Builder):定义创建产品各个部分的接口或抽象类。
- 具体建造者(Concrete Builder):实现抽象建造者的接口,负责构建产品的各个部分。
- 指挥者(Director):负责使用建造者来构建产品。它知道如何顺序调用建造步骤以正确地构造产品。
适用场景
- 当对象需要很多参数来构造,特别是当有些参数是可选的时候。
- 需要生成不同表示的产品时。
- 构造过程必须允许被构造的不同对象独立变化。
代码实现
我们这里日志器对象的实现,刚好符合以上的条件,我们的思路是有一个基类的的建造者类,然后派生出不同职责的建造者:
cpp
//基类建造者
class LoggerBuilder
{
public:
LoggerBuilder()
:_logger_type(loggerType::LOGGER_SYNC)
,_looper_type(logs::AsyncLooper::AsyncType::ASYNC_SAFE)
,_limt_level(Loglevel::value::DEBUG)
{
}
//类型建造
void buildLoggerType(loggerType type)
{
_logger_type = type;
}
void buildEnableUnSafeAsync()
{
_looper_type = logs::AsyncLooper::AsyncType::ASYNC_UNSAFE;
}
void buildLoggerName(const std::string &name)
{
_logger_name = name;
}
void buildLoggerlevel(Loglevel::value level)
{
_limt_level = level;
}
void buildFormatter(const std::string &pattern)
{
_formetter = std::make_shared<Formetter>(pattern);
}
//落地方向构造
template<typename SinkType,typename... Args>
void buildSink(Args &&...args)
{
BaseSink::ptr psink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
_sinks.push_back(psink);
}
virtual BaseLogger::ptr build() = 0;
protected:
logs::AsyncLooper::AsyncType _looper_type; //缓冲区类型
loggerType _logger_type; //日志器类型
std::string _logger_name; //日志器名称
std::atomic<Loglevel::value> _limt_level; //日志输出等级
logs::Formetter::ptr _formetter;
std::vector<BaseSink::ptr> _sinks; //日志输出方向
};
在这个基础上,我们派生出不同类型的建造者:
cpp
//局部建造者
class LocalLogger : public LoggerBuilder
{
public:
BaseLogger::ptr build()
{
assert(_logger_name.empty() == false); //必须有日志器名称
if(_formetter.get() == nullptr)
{
_formetter = std::make_shared<Formetter>();
}
if (_sinks.empty())
{
buildSink<StdoutSink>();
}
if (_logger_type == loggerType::LOGGER_ASYNC)
{
return std::make_shared<AsyncLogger>(_logger_name, _limt_level, _formetter, _sinks, _looper_type);
}
return std::make_shared<SyncLogger>(_logger_name, _limt_level, _formetter, _sinks);
}
};
}
我们可以来测试一下:
cpp
#include "utils.hpp"
#include "level.hpp"
#include "message.hpp"
#include "fometter.hpp"
#include "sink.hpp"
#include "logger.hpp"
// 测试函数
void testLocalLogger()
{
// 创建局部建造者
logs::LocalLogger local_logger;
local_logger.buildLoggerName("synclogger");
local_logger.buildLoggerlevel(logs::Loglevel::value::DEBUG);
local_logger.buildFormatter("abc[%d{%H:%M:%S}][%c]%T%m%n");
logs::BaseLogger::ptr logger = local_logger.build();
logger->debug("main.cc", 53, "%s","格式化功能测试....");
}
int main()
{
testLocalLogger() ;
}

这样大大简化了我们创建对象时的步骤,且不容易出错。