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

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

相关推荐
blasit12 小时前
笔记:Qt C++建立子线程做一个socket TCP常连接通信
c++·qt·tcp/ip
七月丶17 小时前
别再手动凑 PR 了:这个 AI Skill 会按仓库习惯自动建分支、拆提交、提 PR
人工智能·设计模式·程序员
刀法如飞17 小时前
从程序员到架构师:6大编程范式全解析与实践对比
设计模式·系统架构·编程范式
九狼17 小时前
Flutter + Riverpod +MVI 架构下的现代状态管理
设计模式
静水流深_沧海一粟1 天前
04 | 别再写几十个参数的构造函数了——建造者模式
设计模式
StarkCoder1 天前
从UIKit到SwiftUI的迁移感悟:数据驱动的革命
设计模式
肆忆_2 天前
# 用 5 个问题学懂 C++ 虚函数(入门级)
c++
不想写代码的星星2 天前
虚函数表:C++ 多态背后的那个男人
c++
阿星AI工作室2 天前
给openclaw龙虾造了间像素办公室!实时看它写代码、摸鱼、修bug、写日报,太可爱了吧!
前端·人工智能·设计模式
_哆啦A梦3 天前
Vibe Coding 全栈专业名词清单|设计模式·基础篇(创建型+结构型核心名词)
前端·设计模式·vibecoding