全球是邪恶的吗?至少我读过的所有内容都是这样说的,因为某些东西可能随时改变全局的状态。
但是,我有一个DB对象,它在类参数方面有点流浪。下面的属性是一个自动在MS Access或SQL中工作的包装类的实例 - 因此它不是EF或其他ORM。
Public Property db As New DBI.DBI(DBI.DBI.modeenum.access, String.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0} ;Persist Security Info=True;Jet OLEDB:Database Password=""lkjhgfds8928""", GetRpcd("c:\cms")))
代码本身确实有用于异常处理的PostSharp,所以我认为我可以通过记录它们来有条件地处理oledb错误,如果它是Null则重新初始化数据库。
到目前为止,解决方案一直是将db作为参数连续传递给需要它的每个类。大多数数据类都有一个共享的observablecollection,它是由单独实现inotifyproperty改变的结构构建的。其中一个是异步构建的。在触发私有Async buildCollection子类之前,collection属性会检查它是否为空。
鉴于我不需要使用依赖注入,因为我需要学习它;全球财产是不是很糟糕?在拉入或保存数据的任何地方都需要Db。我根本不需要它的唯一地方是View及其背后的代码。
这不是面向客户的项目,但确实需要坚实。
感谢任何建议!
答案 0 :(得分:2)
将数据库连接作为参数传递到您的类中是使用依赖注入,也许您只是不认识它。对调用者中的连接字符串进行硬编码仍然是不依赖的代码,但至少您的数据库访问者本身不依赖于全局连接。
Globals不仅仅是邪恶的,因为它们会在没有通知的情况下发生变化 - 这只是因为糟糕的设计选择而导致的一种效果。它们是邪恶的,因为使用它们的设计是脆弱的。依赖于全局变量的代码需要在调用之前正确设置不可见的东西,这会导致不相关代码之间的相互依赖性。看不见的东西变成了至关重要的东西。只读取内部使用全局变量的模块的接口,我怎么知道在调用它之前我必须调用SetupGlobalThing()方法?如果我以不同的顺序调用IncrementGlobalThing()和DecrementGlobalThing()以及MultiplyGlobalThing()会发生什么情况,具体取决于用户选择的函数?
相反,更喜欢无状态方法,其中传递所有要更改和使用的东西:IncrementThing(整数事物)不依赖于隐藏的设置步骤。它显然做了一件事:它增加了传入的东西。
从单元测试的角度考虑它可能会有所帮助。如果你要编写一个单元测试来证明一个特定的代码模块工作,你需要传递一个真正的数据库连接(硬*),还是你能够传递一个虚假的数据库参考,轻松满足你的测试需求?
测试逻辑的最佳方法是对其进行单元测试。测试类接口和方法结构的最佳方法是编写调用它们的单元测试。如果这个类很难测试,那很可能是因为依赖于外部事物(全局,单例,数据库,不适当的成员变量等)。