【问题标题】:Is it OK to use manager classes as Singletons?可以将管理器类用作单身人士吗?
【发布时间】:2011-04-04 12:35:37
【问题描述】:

对于每个具体类,我都有一个 Manager 类。这个类有GetAll()、GetById()、Save等方法。

我将这些管理器类设为单例,因为我总是需要一个实例,而且我有能力缓存结果。比如当我调用GetAll(),下次我再次需要这个方法时,管理器不用去数据库,它可以返回缓存的结果。

这是一个好方法吗?还是有更好的替代方法?

【问题讨论】:

  • 我不知道这里有足够的信息来具体回答这个问题。我也不确定是否有具体的答案。在某些情况下,能够缓存结果将是一个好主意。如果数据是动态的或数据集很大,缓存它可能不是一个好主意(你会得到陈旧的数据,或者增加不必要的内存压力)。我认为这是非常有情境的。

标签: c# data-access-layer


【解决方案1】:

您所说的管理器类实际上是“存储库”

存储库只能在聚合根级别工作,而不是每个类一个存储库。例如。如果我有一个包含 OrderItem 集合的 Order 类,那么将存在一个具有 Get/GetAll 方法的 Order 存储库 - 因为在这种情况下 Order 是 agg 根。

所有存储库类通常都是单例类,您通常可以通过 IOC 容器轻松地实施这一点。

总体而言,我会说每个实体一个“存储库”的方法是不好的 - 而是坚持每个聚合根一个存储库。

【讨论】:

  • 我认为我从未将存储库实现为单例。我当然使用 DI,但通常每次都注入一个新实例。我应该补充一点,我通常使用“一次请求”模型(Web)并将单个实例注入到处理它的控制器中。 YMMV。
  • @bstack:谢谢。还有一个问题。如何使用 IOC 容器强制执行此操作?你能提供一些(示例)代码吗?
  • @tvanfosson:我不知道如何在我的情况下使用 DI。你能再解释一下吗?
  • @Martijn -- 我使用 Ninject : github.com/ninject/ninject/wiki/_pages (docs)
  • @tvanfosson:如何将它与管理器类一起使用?我要注入什么,注入到哪里?
【解决方案2】:

为什么不将它们作为具体类的一部分而是静态的?省去了两个单独的类。

【讨论】:

  • 因为那会违反SRP原则。
【解决方案3】:

听起来您已经接近实现Repository 模式,但还没有完全实现。我建议调查一下。我不会让它们成为单例——这使得在你的单元测试中模拟它们太难了,所以你最终会添加后门来击败单例进行测试。缓存是一个很好的 Singleton 对象,但为什么不简单地以这种方式共享缓存而不是乘以 Singleton 呢?

【讨论】:

  • +1。我正在写我的答案,但我不能说其他任何事情:)
  • “为什么不简单地以这种方式共享缓存而不是乘以单例”是什么意思。如何共享缓存?你的意思是,将它作为参数传递?
  • @Martijn - 您想引用单个实例,因此要么使用单例缓存,要么使用配置为通过构造函数注入单个实例的 DI 框架。为了支持单元测试,我有时会为 Singleton 创建一个接口并注入该接口的一个实例。这允许您模拟测试。在构造函数中,我检查参数是否为 null(在生产代码中就是这种情况),如果是,则默认为 Singleton 实例。
【解决方案4】:

出于测试/模拟目的,我建议不要使用 Manager/Repository Singleton。

如果您确实想缓存结果,那么我建议委托给专用的 Cache 类。任何静态魔法都可以包含在 Cache 类中,并且可以保持 Manager/Repository 的语义干净。

从单一职责原则的角度来看,我应该能够理解 Manager/Repository 的工作原理,而无需了解您的缓存方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多