C++项目 —— 基于多设计模式下的同步&异步日志系统(5)(建造者模式)

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)

建造者模式是一种创建型设计模式,它允许逐步构建复杂的对象。这种模式对于需要构造具有许多可选组件的对象特别有用。通过使用建造者模式,可以避免构造函数参数列表过长的问题,并且使得代码更加清晰和易于维护。

主要概念
  1. 产品角色(Product):最终需要创建的复杂对象。
  2. 抽象建造者(Builder):定义创建产品各个部分的接口或抽象类。
  3. 具体建造者(Concrete Builder):实现抽象建造者的接口,负责构建产品的各个部分。
  4. 指挥者(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() ;
}

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

相关推荐
是2的10次方啊5 分钟前
设计模式与生活㉒:暖气热不热,得一间一间摸过去
设计模式
ShineWinsu31 分钟前
对于Qt:QTreeWidget常见属性以及QTreeWidgetItem类的解析
开发语言·c++·qt·gui·客户端·多叉树·qtreewidget
落羽的落羽1 小时前
【C++】C++17的主要特性
linux·服务器·开发语言·c++·算法·机器学习
bigbread5 小时前
迭代器模式-在区域健康档案导出中的实战应用
设计模式
汉克老师6 小时前
《从C++小白到算法高手:GESP 1—8级成长地图》第一讲:认识GESP——从编程新手到算法探索者
c++·gesp·信息学竞赛·小学生学c++
装不满的克莱因瓶7 小时前
设计模式之策略模式核心概念和应用场景
java·后端·设计模式·架构·系统架构·策略模式
晴天的雨.9928 小时前
【C++】继承篇
java·开发语言·c++
青少儿编程课堂8 小时前
蓝桥杯青少组图形化 + 全国青少年信息素养大赛 + 电子学会图形化考级:校园大富翁经营闯关解析
c++·python·算法·bfs·信息学竞赛
another heaven8 小时前
【C/C++ 第一次跨越(上):用 C++11/14 停止制造新的旧代码】
c语言·c++·制造
qq_406981038 小时前
c++ lamda(三)Lambda表达式
java·前端·c++