
日志与策略模式什么是设计模式IT行业这么火涌入的人很多俗话说林子大了啥鸟都有。大佬和菜鸡们两极分化的越来越严重。为了让菜鸡们不太拖大佬的后腿于是大佬们针对一些经典的常见的场景给定了一些对应的解决方案这个就是设计模式。认识日志计算机中的日志是记录系统和软件运行中发生事件的文件主要作用是监控运行状态、记录异常信息帮助快速定位问题并支持程序员进行问题修复。它是系统维护、故障排查和安全管理的重要工具。日志已有现成的解决方案如spdlog、glog、Boost.Log等等。日志的格式有以下的标准1.时间戳 2.日志的等级 3.日志的内容还可以加入1.文件名 2.行号 3.线程or进程的id这里我们采用设计模式 - 策略模式来进行日志的设计我们想要实现的日志格式如下代码语言javascriptAI代码解释[可读性很好的时间] [⽇志等级] [进程pid] [打印对应⽇志的⽂件名][⾏号] - 消息内容⽀持可变参数 [2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [16] - hello world [2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [17] - hello world [2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [18] - hello world [2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [20] - hello world [2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [21] - hello world [2024-08-04 12:27:03] [WARNING] [202938] [main.cc] [23] - hello world前提实现日志需要使用到锁这里我们可以使用上一篇文章中封装好了的锁接口。【Linux系统】深入理解线程同步实现生产消费模型-CSDN博客代码语言javascriptAI代码解释Mutex.hpp // 封装锁接口 #pragma once #include pthread.h class Mutex { public: Mutex() { pthread_mutex_init(mutex, nullptr); } ~Mutex() { pthread_mutex_destroy(mutex); } void Lock() { pthread_mutex_lock(mutex); } void Unlock() { pthread_mutex_unlock(mutex); } private: pthread_mutex_t mutex; }; class LockGuard { public: LockGuard(Mutex mutex) : _Mutex(mutex) { _Mutex.Lock(); } ~LockGuard() { _Mutex.Unlock(); } private: // 为了保证锁的底层逻辑锁是不能够拷贝的并且也是没有拷贝构造函数的 // 避免拷贝应该引用 Mutex _Mutex; };日志刷新策略实现日志的刷新策略可以分为两种向屏幕刷新、向指定文件刷新第一步先实现日志中的刷新策略我们可以通过C中的继承与多态来实现日志选择不同的刷新策略。基类作为抽象类没有任何方法实现不同的子类来继承后实现不同的刷新方式其中不论是显示器刷新还是指定文件刷新其都是临界资源不能同时访问写入数据否则将会导致信息错乱。所有刷新的过程全部都要加锁向显示器刷新没什么好说的向文件刷新其中对文件的路径要进行判断如果文件的路径不存在则需要我们创建对应的路径。其中需要使用的接口如下代码语言javascriptAI代码解释#include filesystem //C17标准 命名空间std::filesystem 位于filesystem命名空间中 判断路径p是否存在返回boolexists(const path p) 创建对应的路径 create_directories(const path p)打开对应的路径代码语言javascriptAI代码解释#include fstream 命名空间std 位于std命名空间中 创建对象时打开文件: ofstream ofs(path,openmode) 打开模式设置为追加模式ios::app具体实现代码语言javascriptAI代码解释const string end \r\n; // 实现刷新策略a.向显示器刷新 b.向指定文件刷新 // 利用多态机制实现 // 包含至少一个纯虚函数的类称为抽象类不能实例化只能被继承 class LogStrategy // 基类 { public: //0声明为纯虚函数。纯虚函数强制派生类必须重写该函数 virtual void SyncLog(const string message) 0; }; // 向显示器刷新子类 class ConsoleLogStrategy : public LogStrategy { public: void SyncLog(const string message) override { // 加锁访问显示器显示器也是临界资源 LockGuard lockguard(_mutex); cout message end; } private: Mutex _mutex; }; // 向指定文件刷新子类 const string defaultpath ./log; const string defaultfile my.log; class FileLogStrategy : public LogStrategy { public: FileLogStrategy(const string path defaultpath, const string file defaultfile) : _path(path), _file(file) { LockGuard lockguard(_mutex); // 判断路径是否存在,如果不存在就创建对应的路径 if (!(filesystem::exists(_path))) filesystem::create_directories(_path); } void SyncLog(const string message) override { // 合成最后路径 string Path _path (_path.back() / ? : /) _file; // 打开文件 ofstream out(Path, ios::app); //以流方式向文件写入数据 out message end; } private: string _path; string _file; Mutex _mutex; };日志文件生成与选择刷新策略实现完成日志文件的刷新策略下面实现日志文件的形成与刷新策略的选择。第二步实现日志文件对刷新策略的选择利用多态机制灵活选择刷新策略代码语言javascriptAI代码解释class Logger { public: Logger() { // 默认选择显示器刷新 Strategy make_uniqueConsoleLogStrategy(); } //选择在显示器刷新 void EnableConsoleLogStrategy() { Strategy make_uniqueConsoleLogStrategy(); } //选择向指定文件刷新 void EnableFileLogStrategy() { Strategy make_uniqueFileLogStrategy(); } private: //智能指针 unique_ptrLogStrategy Strategy; };第三步实现日志文件的生成我们选择Logger类中实现LogMessage类的方式,来实现日志信息。补充外部类只能通过内部类的实例化对象来访问内部类中的方法与成员且受修饰符限制。 内部类可以直接访问外部类的方法以及成员没有限制。