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() ;
}

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

相关推荐
折哥的程序人生 · 物流技术专研12 分钟前
Java 23 种设计模式:从踩坑到精通 | 适配器模式 —— 让不兼容的接口也能一起工作
java·设计模式·面试·适配器模式·单一职责原则
Rabitebla17 分钟前
C++ 多态详解:从概念到虚表底层原理(代码轰炸)
开发语言·c++
charlie11451419121 分钟前
通用GUI编程技术——图形渲染实战(五十)——命中测试与鼠标事件路由:精确交互
c++·windows·架构·交互·图形渲染
布朗克16823 分钟前
33 设计模式精讲
java·单例模式·设计模式
hetao173383730 分钟前
2026-05-25~06-11 hetao1733837 的刷题记录
c++·算法
洛水水35 分钟前
【力扣100题】82.有效的括号
c++·算法·leetcode
初中就开始混世的大魔王1 小时前
7 Fast DDS-持久化服务
c++·人工智能·中间件·自动驾驶·信息与通信
爱吃生蚝的于勒1 小时前
QT开发第三章——常用控件
linux·服务器·开发语言·前端·javascript·c++·qt
Shadow(⊙o⊙)2 小时前
QT常用控件1.0,enabled() geometry() QIcon的.qrc文件导入
开发语言·c++·qt
geovindu2 小时前
python: Generators Pattern
开发语言·python·设计模式·生成器模式