首先让我说“logger”是指负责向用户或程序员报告诊断或进度信息的任何类对象。根据这个定义,“记录器”将包括GUI上的反馈,例如进度条。
我们一再被告知要避免全球状态,尤其是全球可变状态(GMS)。由于记录器本质上是可变的,我最近试图使我的记录器“不是全局的”。我尝试了各种策略(比如通过构造函数注入对记录器的引用)。我终于意识到所有这些方法都只是在口红上涂上口红。
如果记录器有用,则所有类(或至少大多数类)都必须可以访问它。因此它是全球性的。它必须是可变的;记录器的文件无法附加有什么用呢?或者进度条的值不能改变?如果您使记录器成为单例,或者使用依赖注入,或创建静态方法来保存引用,则无关紧要。无论你如何切片,记录器都将成为GMS。
我能做的最好的事情就是创建一个非常小的容器类,它(静态地)创建记录器,并通过静态方法引用该记录器(全局)。
所以最后我的问题。 当我们谈论GMS时,记录器真的是我们担心的吗?你写信给它,但你(几乎)从不读它。记录器真的是GMS吗?
必须静态创建全局记录器,至少在Java中,因此可以通过静态方法访问它。这使得测试很痛苦。但是我们能做些什么呢?
答案 0 :(得分:1)
简答:从技术上讲,您描述的记录器是GMS,但不是,当我们谈论GMS时,它们并不是我们所担心的。原因是它们本质上是只写,因此状态不会影响程序其余部分的任何内容。当然,你必须确保它们实际上是只写的,尽可能合理(即通常可以不担心你的文件记录器填满了文件系统;它不会没有问题。问它到目前为止记录了多少行。
关于你的测试问题:记录器本身当然可以是一个普通的类,可以自己测试。其他代码与记录器的唯一全局实例的交互是一种难以测试的问题,因此通常最好只使这些代码完全最小和简单,并使它们不经过测试。
如果你真的想测试它们,一个务实的解决方案是给那个容器类setInstance
以及getInstance
。在这种情况下,最好使默认的类实例化记录器实际上是一个无操作的记录器,并让主应用程序通过setInstance
初始化真实的生产记录器。
理论华夫饼干:" Global"字面意思只是意味着它可以从任何地方访问(全局访问)。它通常也意味着它只有一个(全局,如小写单例)。通常由这两个问题引起的问题是:
通常,在(全球!)类中包装某些东西并不会使它变得不那么全局 - 它仍然可以被任何人访问,并且默认情况下会出现这种情况。仍然只有一个。唯一的优势在于,特别是在Java中,它使代码看起来更加自律,并传达了您对此问题的看法。
可以解决全球单身人士的问题,例如:与工厂模式类似,但对于可能预生成的对象,这将解决替代实例问题。
全球访问问题是AFAICT无法解决的问题,但可以通过对谁获得访问权限(使对象不完全全局)的更精细控制来减轻这些问题,将实例传递给每个可能的构造函数(或方法调用),手动或通过一些依赖注入库。手动解决方案当然是对于样板代码; DI libs具有学习曲线,与普通全局变量相比仍然是非零样板。
特别是对于记录器的描述,#1被视为一个可接受的假设,即字面上每一段代码都可能记录一些东西; #2由记录器解决,保证尽管可变,但它无法让其他代码隐蔽地或偶然地相互影响;和#3可以通过setInstance
这个东西来解决,一个非常简单的"" Factory-oid解决方案的变体。