c# - 这是对静态属性的错误使用吗?

标签 c# design-patterns dependency-injection static-members

如果我有一个带有服务的类,我希望所有派生类都可以访问(比如安全对象或存储库),那么我可能会这样做:

public abstract class A
{
    static ISecurity _security;
    public ISecurity Security { get { return _security; } }

    public static void SetSecurity(ISecurity security) { _security = security; }
}

public class Bootstrapper
{
    public Bootstrapper()
    {
        A.SetSecurity(new Security());
    }
}

似乎最近我看到静态属性在任何地方都被回避作为绝对避免的东西。对我来说,这似乎比将 ISecurity 参数添加到我创建的每个派生类的构造函数中更干净。考虑到我最近阅读的所有内容,我想知道:

这是一个可以接受的依赖注入(inject)应用,还是我违反了一些主要的设计原则,以后可能会回来困扰我?我此时没有进行单元测试,所以如果当时我可能会突然意识到我的问题的答案。老实说,虽然我可能不会为此更改我的设计,但如果有其他重要原因我应该更改它,那么我很可能会这样做。

编辑:我第一次编写该代码时犯了几个愚蠢的错误……现在已修复。只是想我会指出这一点,以防万一有人注意到 :)

编辑:SWeko 提出了一个很好的观点,即所有派生类都必须使用相同的实现。在我使用这种设计的情况下,该服务始终是单例,因此它有效地执行了一个已经存在的要求。当然,如果不是这样,这将是一个糟糕的设计。

最佳答案

这种设计可能有几个问题。

您已经提到单元测试,这是相当重要的。这种静态依赖性会使测试变得更加困难。当伪造的 ISecurity 必须是 Null Object 以外的任何东西时实现,你会发现自己不得不在测试拆除时删除虚假实现。在测试拆卸期间将其移除可防止在您忘记移除该假对象时影响其他测试。测试拆卸会使您的测试更加复杂。并没有那么复杂,但是当许多测试都拆解代码时,这会加起来,并且当一个测试忘记运行拆解时,您将很难在测试套件中找到错误。您还必须确保注册的 ISecurity 假对象是线程安全的,并且不会影响可能并行运行的其他测试(出于明显的性能原因,MSTest 等测试框架并行运行测试) .

将依赖项作为静态注入(inject)的另一个可能的问题是,您强制此 ISecurity 依赖项成为单例(并且可能是线程安全的)。例如,这不允许应用任何拦截器和 decorators与单例有着不同的生活方式

另一个问题是,从构造函数中删除此依赖项会禁用 DI 框架可以代表您完成的任何分析或诊断。由于您手动设置了此依赖项,因此框架不知道此依赖项。从某种意义上说,您将管理依赖项的责任移回了应用程序逻辑,而不是允许 Composition Root控制依赖关系连接在一起的方式。现在应用程序必须知道 ISecurity 实际上是线程安全的。这是通常属于 Composition Root 的责任。

您想要将此依赖项存储在基类型中的事实甚至可能表明违反了一般设计原则:Single Responsibility Principle (建议零售价)。它与我过去犯的一个设计错误有些相似。我有一组业务操作,它们都继承自一个基类。这个基类实现了各种行为,例如事务管理、日志记录、审计跟踪、添加容错以及……添加安全检查。这个基类变得难以管理 God Object .它难以管理,仅仅是因为它有太多的责任;它违反了 SRP。 Here's my story如果您想了解更多。

因此,与其在基类中实现此安全问题(这可能是一个横切问题),不如尝试将基类全部删除,并使用装饰器为这些类添加安全性。您可以用一个或多个装饰器包装每个类,每个装饰器可以处理一个特定的问题。这使得每个装饰器类都易于遵循,因为它们将遵循 SRP。

关于c# - 这是对静态属性的错误使用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14625278/

相关文章:

c# - 当另一个网格元素设置为折叠时,WPF 网格元素不调整大小

c# - 如何保存游戏状态?

c# - 如何在 LINQ 中使用 GroupBy 查找丢失的项目?

java - 这段代码是否滥用了观察者模式?

java - Guice/DI 和混合注入(inject)和运行时传入的参数

c# - 使用新的 .net-core-3 json 序列化程序进行依赖注入(inject)

c# - 如何在 .NET Framework 3.5 上使用 Stream.CopyTo?

c# - 反DRY模式

c# - 这段代码是合适的 MVC 架构吗?

hibernate - JSR-303 依赖注入(inject)和 Hibernate