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

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

相关推荐
点云SLAM12 分钟前
C++中的算术转换、其他隐式类型转换和显示转换详解
c++·static_cast·dynamic_cast·c++中的类型转换·算术类型转换·其他隐式类型转换·显示类型转换
Zfox_39 分钟前
Git 进阶之路:高效协作之分支管理
大数据·linux·运维·c++·git·elasticsearch
wenchm1 小时前
细说STM32单片机FreeRTOS任务管理API函数vTaskList()的使用方法
c语言·c++·stm32·单片机·嵌入式硬件
wuqingshun3141591 小时前
蓝桥杯 10.拉马车
数据结构·c++·算法·职场和发展·蓝桥杯·深度优先
不是仙人的闲人2 小时前
算法之动态规划
数据结构·c++·算法·动态规划
rigidwill6662 小时前
LeetCode hot 100—分割等和子集
数据结构·c++·算法·leetcode
眠りたいです2 小时前
Linux-网络基础
linux·运维·服务器·网络·c++·进程间通信
姝孟2 小时前
学习笔记(C++篇)--- Day 3
c++·笔记·学习
碎梦归途3 小时前
23种设计模式-结构型模式之代理模式(Java版本)
java·开发语言·jvm·设计模式·代理模式
天狗精灵3 小时前
狗教我React—— 5 种组件提取思路与实践
前端·react.js·设计模式