c ++:没有全局或单例的logger类或将其传递给每个方法

Din*_*aiz 20 c++ logging singleton dependency-injection

有没有人知道是否可以像没有记录器一样的类:

  • 使用单例或全局(la std :: cout)

  • 将实例/指针/引用传递给需要它的每个方法

我以一个记录器类为例,但我的应用程序中有一些类可以从中受益(例如,撤消管理器).

每个解决方案都有几个问题:

  • 使用单例对于测试来说是有问题的(还有许多原因,使用单例通常不是一个好主意).全球化也是如此.此外,没有什么可以保证应用程序中只有一个实例,甚至不是一个要求(例如,为什么没有2个记录器?)

  • 将它传递给每个对象构造函数(依赖注入),导致很多样板代码,并且可能容易出错,因为你必须多次复制/粘贴相同的代码.可以认真考虑在每个类的构造函数中都有一个指向Logger的指针???????

所以我想知道是否有第三种选择,在C++中,我从未听说过?对我而言,听起来它需要一些黑魔法引擎盖,但我对我在堆栈溢出中学到的一些技术感到惊喜,这是我在google中找不到的,所以我知道这里有一些真正的大师;)

令人惊讶的是,我发现了许多关于如何设计单身人士的讨论,或者为什么不应该使用单身人士,但我找不到一个解决我的问题的帖子......

Qua*_*nic 10

我想你可以做类似于使用Log4j包在Java中完成的事情(可能是用它的Log4c版本完成的):

有一个可以返回多个记录器实例的静态方法:

Logger someLogger = Logger.getLogger("logger.name");
Run Code Online (Sandbox Code Playgroud)

getLogger()方法不返回单个对象.它返回命名的记录器(必要时创建它). Logger只是一个接口(在C++中它可能是一个完全抽象的类) - 调用者不需要知道Logger正在创建的对象的实际类型.

你可以继续模仿Log4j并且重载getLogger()也需要一个工厂对象:

Logger someLogger = Logger.getLogger("logger.name", factory);
Run Code Online (Sandbox Code Playgroud)

该调用将用于factory构建记录器实例,使您可以更好地控制Logger正在创建的底层对象,这可能有助于您进行模拟.

因此,不需要将任何内容传递给您自己的代码的构造函数,方法等.您只需在需要Logger时抓取所需的名称并登录即可.根据您编写的日志记录代码的线程安全性,您可以getLogger()返回类的静态成员,因此您只需getLogger()每个类调用一次.

  • 我真的没有看到这对单身人士的好处.如果他们都必须包装一些错误日志文件句柄,那么该文件句柄已经是单例.使用单个one-member-field结构或简单的单例类来包装它只包含文件指针成员,并且没有虚方法只等同于单例文件句柄对象.我也不喜欢单身人士,但这并不是一种有利的方式.它基本上是getSingletonSuitableFor(someParam). (2认同)

Bet*_*eta 6

有一些静态方法的类怎么样?

class Logger
{
public:
  static void record(string message)
  {
    static ofstream fout("log");
    fout << message << endl;;
  }
  ...
};

...

void someOtherFunctionSomewhere()
{
  Logger::record("some string");
  ...
}
Run Code Online (Sandbox Code Playgroud)

没有Singleton,没有全局变量,但是任何可以看到的代码都Logger.h可以调用成员函数,并且如果所有公共成员函数都返回void,则很容易将其存根用于测试.