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 小时前
LeetCode 852:山脉数组的峰顶索引(二分查找) —— 题解
数据结构·c++·算法·leetcode·二分查找
程与留2 小时前
05_Qt 核心模块概览——Qt Core、Gui、Widgets、Quick 的职责划分
c++·qt
buhuizhiyuci3 小时前
【QT-百日筑基篇】修真世界摸爬滚打多年,终于黄天不负有心人,突破炼器中期——常用控件QWight的属性
开发语言·c++·qt·gui·图形化
冻柠檬飞冰走茶6 小时前
《数据结构实验指导-C++语言版》 求单链表list中的元素个数,即表长
开发语言·数据结构·c++·算法·list
_Narcissus_6 小时前
动态规划初探(含完整代码实现)
c语言·数据结构·c++·算法·动态规划·背包问题·最短路径
法哥20127 小时前
用 C++ 控制 CMW100,到底在干什么?
开发语言·c++
AI人工智能+电脑小能手8 小时前
大白话说Java设计模式-28-模板方法模式(业务实战篇)
java·设计模式·模板方法模式·spring源码·订单系统·代码复用
_Narcissus_8 小时前
枚举和模拟算法笔记
c语言·数据结构·c++·笔记·算法·模拟·枚举
冻柠檬飞冰走茶8 小时前
《数据结构实验指导-C++语言版》 在顺序表 list 中查找元素 x
开发语言·数据结构·c++·算法·list
Brilliantwxx8 小时前
【C++】 高阶数据结构图(1)并查集
开发语言·数据结构·c++