在OOP上下文中正确登录

时间:2020-03-05 18:59:45  来源:igfitidea点击:

自从我开始学习面向对象的编程以来,这就是我一直在努力的一个问题:一个人应该如何用"适当的" OOP代码实现记录器?

我的意思是说,一个对象具有一种方法,我们希望代码中的所有其他对象都可以访问;此方法将输出到console / file / every,我们将使用它进行日志记录-因此,此对象将是logger对象。

我们不想将记录器对象建立为全局变量,因为全局变量不好,对吧?但是我们也不想让在每个对象中调用的每个方法的参数中都通过logger对象。

在大学里,当我提起这件事给教授时,他实际上无法给我答案。我意识到实际上有一些软件包(例如Java)可以实现此功能。不过,我最终要寻找的是如何正确地并以OOP方式自己实现这一点的知识。

解决方案

回答

我们可以看一下Singleton模式。

回答

将记录器创建为单例类,然后使用静态方法访问它。

回答

我一直使用Singleton模式来实现日志记录对象。

回答

我认为我们应该为此使用AOP(面向方面​​的编程),而不是OOP。

回答

我们确实希望将记录器建立为全局变量,因为全局变量还不错。至少,它们并不是天生的坏。记录器是正确使用全局可访问对象的一个​​很好的例子。如果需要更多信息,请阅读有关Singleton设计模式的信息。

回答

我认为,在实践中,单例/全局方法很好用。最好全局对象只是一个框架,我们可以将不同的侦听器(观察者模式)连接到该框架,例如一种用于控制台输出,一种用于数据库输出,一种用于Windows EventLog输出,等等。

但是要提防过度设计,我发现在实践中,只有全局方法的单个类可以很好地工作。

或者,我们可以使用我们提供的特定框架的基础结构。

回答

来自Microsoft的Pattern&Practices组的企业库日志记录应用程序块是在OOP环境中实现日志记录框架的一个很好的例子。他们有一些很棒的文档,说明了如何实现其日志记录应用程序块,并且所有源代码都可供我们自己查看或者修改。

还有其他类似的实现:log4net,log4j,log4cxx

他们实现企业库日志记录应用程序块的方式是拥有一个静态Logger类,该类具有许多实际执行日志操作的不同方法。如果我们正在研究模式,那么这可能是Singleton模式的更好用途之一。

回答

有一些经过深思熟虑的解决方案。其中一些涉及绕过OO,并使用另一种机制(AOP)。

日志记录并不能很好地适合OO(没关系,并非所有事情都可以)。如果我们必须自己实现它,建议我们在每个类的顶部实例化" Log":

private final log = new Log(this);

然后我们所有的日志记录调用都是微不足道的:log.print(" Hey");

这比单例更易于使用。

让记录器确定我们要传入的类,然后使用该类来注释日志。由于我们有了日志实例,因此可以执行以下操作:

log.addTag(" Bill");

日志可以将标签帐单添加到每个条目,以便我们可以对显示进行更好的过滤。

log4j和电锯是一种完美的即用型解决方案-如果我们不只是在学习,请使用它们。

回答

我全都支持AOP和log4 *。这确实帮助了我们。
例如,谷歌给我这篇文章。我们可以尝试在该主题上进行更多搜索。

回答

(IMHO)"记录"的发生方式不是解决方案设计的一部分,它更多地是运行在Java和System(如Calendar)中的任何环境的一部分。

"好"解决方案是尽可能松散地耦合到任何特定日志记录实现的解决方案,因此请考虑接口。我将在这里查看有关Sun如何解决该问题的示例,因为他们可能提出了一个非常好的设计并将其全部布置供我们学习!

回答

使用静态类,它具有最少的开销,并且可以在简单的程序集引用中从所有项目类型进行访问

请注意,单例是等效的,但涉及不必要的分配

如果我们使用的是多个应用程序域,请注意,可能需要一个代理对象才能从主域以外的域访问静态类。

另外,如果我们有多个线程,则可能需要锁定日志记录功能以避免交错输出

仅IMHO日志记录是不够的,这就是为什么我写CALM的原因

祝你好运!

回答

也许以透明的方式插入Logging宁愿属于"面向方面的编程"习惯用法。但是我们在这里谈论OO设计...

我认为Singleton模式可能是最有用的:我们可以通过LoggingService类的公共静态方法从任何上下文访问Logging服务。

尽管这看起来很像一个全局变量,但事实并非如此:它被正确地封装在singleton类中,并且不是每个人都可以访问它。这使我们即使在运行时也可以更改日志记录的处理方式,但可以保护日志记录免受"恶意"代码的影响。

在我工作的系统中,我们创建了多个Logging'singletons',以便能够区分来自不同子系统的消息。这些可以在运行时打开/关闭,可以定义过滤器,可以写入文件...命名。

回答

过去,我已经通过将日志记录类的实例添加到需要访问日志记录的类的基类(或者接口,如果语言支持),来解决此问题。当我们记录某些内容时,记录器会查看当前的调用堆栈并从中确定调用代码,并设置有关记录语句的适当元数据(源方法,代码行(如果有),记录的类等)。许多类具有记录器,并且不需要使用可以自动确定的元数据来专门配置记录器。

这的确增加了相当大的开销,因此对于生产日志记录而言,它不一定是明智的选择,但是如果我们以这种方式进行设计,则可以有条件地禁用日志记录器的各个方面。

实际上,我大部分时间都使用commons-logging(我在Java中做了很多工作),但是我在上面描述的设计中有一些方面是有益的。使用健壮的日志系统(其他人已经花费大量时间进行调试)的好处超过了对可以被视为更简洁设计的需求(显然这是主观的,尤其是鉴于本文中没有详细说明)。

我在静态记录器方面遇到了问题,导致了permgen内存问题(至少,我认为这就是问题所在),所以我可能很快会重新讨论记录器。

回答

全球可访问的记录器是测试的难题。如果需要"集中式"日志记录工具,请在程序启动时将其创建,然后将其注入需要日志记录的类/方法中。
我们如何测试使用类似以下内容的方法:

public class MyLogger 
{
    public static void Log(String Message) {}
}

我们如何用模拟代替它?

更好的:

public interface ILog 
{
    void Log(String message);
}

public class MyLog : ILog 
{
    public void Log(String message) {}
}

回答

另一种可能的解决方案是拥有一个Log类,该类封装了日志记录/存储过程。这样,我们就可以在需要时实例化一个新的Log();,而不必使用单例。

这是我的首选解决方案,因为如果要通过数据库进行日志记录,则只需注入数据库。如果我们正在使用文件,则无需注入任何依赖项。我们也可以完全避免使用全局或者静态日志记录类/函数。

回答

为避免全局变量,我建议创建一个全局注册表,并在此处注册全局变量。

对于日志记录,我更喜欢提供单例类或者提供一些静态日志记录方法的类。

实际上,我将使用现有的日志记录框架之一。