自从我第一次开始学习面向对象编程以来,我一直在努力解决这个问题:如何在“正确的”OOP代码中实现记录器?
通过这个,我的意思是一个对象,它有一个方法,我们希望代码中的每个其他对象都能够访问;此方法将输出到console / file / whatever,我们将用于记录 - 因此,此对象将是记录器对象。
我们不想将记录器对象建立为全局变量,因为全局变量很糟糕,对吧?但是我们也不希望在每个单个对象中调用的每个方法的参数中都传递logger对象。
在大学里,当我把它带给教授时,他实际上无法给我一个答案。我意识到实际上有可能实现此功能的包(例如Java)。不过,我最终要找的是如何正确地以OOP方式实现这一点的知识。
答案 0 :(得分:13)
你做想要将记录器建立为全局变量,因为全局变量不坏。至少,它们本身并不坏。记录器是正确使用全局可访问对象的一个很好的例子。如果您想了解更多信息,请阅读Singleton设计模式。
答案 1 :(得分:4)
有一些经过深思熟虑的解决方案。有些涉及绕过OO并使用其他机制(AOP)。
记录对OO来说并没有太好用(这没关系,不是一切都好)。如果你必须自己实现它,我建议只在每个类的顶部实例化“Log”:
private final log = new Log(this);
然后你所有的日志记录调用都是微不足道的:log.print(“嘿”);
这使得它比单身人士更容易使用。
让您的记录器确定您传入的类,并使用它来注释日志。既然你有一个log实例,那么你可以做以下事情:
log.addTag( “比尔”);
日志可以为每个条目添加标签帐单,以便您可以为显示器实现更好的过滤。
log4j和电锯是一个完美的开箱即用解决方案 - 如果你不仅仅是学术上的,那就使用它们。
答案 2 :(得分:2)
全局可访问的记录器很难进行测试。如果需要“集中式”日志记录工具,请在程序启动时创建它并将其注入需要日志记录的类/方法中。 你如何测试使用这样的方法:
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) {}
}
答案 3 :(得分:1)
我一直使用Singleton模式来实现日志记录对象。
答案 4 :(得分:0)
你可以看一下Singleton模式。
答案 5 :(得分:0)
将记录器创建为单例类,然后使用静态方法访问它。
答案 6 :(得分:0)
我认为你应该使用AOP(面向方面编程),而不是OOP。
答案 7 :(得分:0)
在我看来,在实践中,单例/全局方法运行正常。优选地,全局事物只是可以连接不同侦听器(观察者模式)的框架,例如,一个用于控制台输出,一个用于数据库输出,一个用于Windows EventLog输出等。
请注意过度设计,我发现在实践中,只使用全局方法的单个类可以很好地工作。
或者您可以使用您所使用的特定框架提供的基础架构。
答案 8 :(得分:0)
来自Microsoft的Pattern& amp;的Enterprise Library Logging Application Block Practices组是在OOP环境中实现日志框架的一个很好的例子。他们有一些很好的文档,说明他们如何实现他们的日志应用程序块,所有源代码都可供您自己审查或修改。
还有其他类似的实现:log4net, log4j, log4cxx
他们实现企业库日志应用程序块的方式是使用一个静态Logger
类,其中包含许多实际执行日志操作的不同方法。如果您正在查看模式,这可能是Singleton模式的更好用途之一。
答案 9 :(得分:0)
我和log4 *一起用于AOP。这真的帮助了我们。 例如,谷歌给了我this article。您可以尝试在该主题上进行更多搜索。
答案 10 :(得分:0)
您的'好'解决方案是尽可能松散地耦合到任何特定的日志记录实现,因此请考虑接口。我会查看路径here,了解Sun如何处理它,因为它们可能提出了一个非常好的设计,并为您提供了一些可供学习的内容!
答案 11 :(得分:0)
使用静态类,它具有最小的开销,可以从简单的程序集引用中的所有项目类型访问
请注意,Singleton是等效的,但涉及不必要的分配
如果您使用的是多个应用域,请注意您可能需要一个代理对象才能从主要域以外的域访问静态类
如果您有多个线程,则可能需要锁定日志记录功能以避免交错输出
单独恕我直言的记录是不够的,这就是我写CALM
的原因 祝你好运!答案 12 :(得分:0)
也许以透明方式插入Logging宁可属于面向方面编程习语。但我们在这里谈论OO设计......
在我看来,Singleton模式可能是最有用的:您可以通过LoggingService类的公共静态方法从任何上下文访问Logging服务。
虽然这看起来很像一个全局变量,但它不是:它被正确封装在单例类中,并不是每个人都可以访问它。这使您可以更改即使在运行时处理日志记录的方式,但可以保护日志记录的工作免受“vilain”代码的影响。
在我工作的系统中,我们创建了许多Logging“单例”,以便能够区分来自不同子系统的消息。这些可以在运行时打开/关闭,可以定义过滤器,可以写入文件......你可以命名。
答案 13 :(得分:0)
我过去通过向需要访问日志记录的类的基类(或接口,如果语言支持)添加日志记录类的实例来解决这个问题。当您记录某些内容时,记录器会查看当前调用堆栈并确定从中调用代码,设置有关日志记录语句的正确元数据(源方法,代码行(如果可用),记录的类等等)这种方式最小化类的数量有记录器,并且记录器不需要专门配置可以自动确定的元数据。
这个 会增加相当大的开销,因此它不一定是生产日志记录的明智选择,但如果您以这种方式设计它,则可以有条件地禁用记录器的各个方面。
实际上,我大部分时间都在使用commons-logging(我在java中做了很多工作),但是我上面描述的设计有些方面我认为很有用。拥有一个其他人已经花费大量时间调试的强大日志记录系统的好处超过了对可以被认为是更清洁设计的需求(这显然是主观的,特别是考虑到这篇文章中缺乏细节)。
我遇到了导致permgen内存问题的静态记录器问题(至少,我认为这就是问题所在),所以我很快就会重新访问记录器。
答案 14 :(得分:0)
另一种可能的解决方案是使用一个Log类来封装日志记录/存储过程。这样,您可以在需要时实例化new Log();
,而无需使用单例。
这是我首选的解决方案,因为如果您通过数据库进行日志记录,则需要注入的唯一依赖项是数据库。如果您正在使用文件,则无需注入任何依赖项。您还可以完全避免全局或静态日志记录类/函数。
答案 15 :(得分:0)
为了避免全局变量,我建议创建一个全局REGISTRY并在那里注册你的全局变量。
对于日志记录,我更喜欢提供单例类或提供一些静态方法进行日志记录的类。
实际上,我会使用其中一个现有的日志记录框架。