C# 可以将管理器类作为单例使用吗?

C# 可以将管理器类作为单例使用吗?,c#,data-access-layer,C#,Data Access Layer,对于每个具体的类,我都有一个经理类。此类具有类似于GetAll(),GetById(),Save等方法 我将这些管理器类设置为单例,因为我总是需要一个实例,并且我能够缓存结果。例如,当我调用GetAll()并且下次我再次需要此方法时,管理器不必转到数据库,它可以返回缓存的结果 这是一个好方法吗?或者有更好的替代方法吗?为什么不将它们作为具体类的一部分,而是静态的?省去了对两个独立类的需要。为什么不将它们作为具体类的一部分,而将其包含在静态类中?节省了对两个独立类的需要。您所谓的管理器类实际上是“

对于每个具体的类,我都有一个经理类。此类具有类似于
GetAll()
GetById()
Save
等方法

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


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

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

为什么不将它们作为具体类的一部分,而将其包含在静态类中?节省了对两个独立类的需要。

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

存储库应该只在聚合根级别工作,而不是每个类一个存储库。例如,如果我有一个Order类,它有一个OrderItem集合,那么就存在一个Order存储库,该存储库将具有Get/GetAll方法,因为在本例中Order是agg根

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


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

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

存储库应该只在聚合根级别工作,而不是每个类一个存储库。例如,如果我有一个Order类,它有一个OrderItem集合,那么就存在一个Order存储库,该存储库将具有Get/GetAll方法,因为在本例中Order是agg根

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


总的来说,我认为您的每个实体一个“存储库”的方法是不好的——而是坚持每个聚合根一个存储库。

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

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

出于测试/模拟目的,我建议不要使用管理器/存储库单例

如果您确实想要缓存结果,那么我建议将其委托给一个专用的缓存类。任何静态魔法都可以包含在Cache类中,并且您的管理器/存储库的语义可以保持干净


从单一责任原则的角度来看,我应该能够理解管理器/存储库是如何工作的,而不必了解您的缓存方案。

出于测试/模拟的目的,我建议不要使用管理器/存储库单例

如果您确实想要缓存结果,那么我建议将其委托给一个专用的缓存类。任何静态魔法都可以包含在Cache类中,并且您的管理器/存储库的语义可以保持干净


从单一责任原则的角度来看,我应该能够理解管理器/存储库是如何工作的,而不必了解您的缓存方案。

因为这将违反SRP原则。因为这将违反SRP原则。我不知道这里是否有足够的信息来具体回答这个问题。我也不确定是否有具体的答案。在某些情况下,能够缓存结果将是一个好主意。如果数据是动态的或数据集很大,缓存它可能不是一个好主意(您会得到过时的数据,或者增加不必要的内存压力)。我认为这是一个非常情境化的问题。我不知道这里有足够的信息来具体回答这个问题。我也不确定是否有具体的答案。在某些情况下,能够缓存结果将是一个好主意。如果数据是动态的或数据集很大,缓存它可能不是一个好主意(您会得到过时的数据,或者增加不必要的内存压力)。我认为这是一个很有情境性的问题。我正在写我的答案,但我不能告诉其他任何事情:)你所说的“为什么不简单地以这种方式共享缓存,而不是增加单例数”是什么意思。如何共享缓存?您的意思是,将其作为参数传递吗?@Martijn-您希望引用单个实例,因此可以使用单例缓存,或者使用配置为通过构造函数注入单个实例的DI框架。为了支持单元测试,我有时为单例创建了一个接口,并注入了该接口的一个实例。这允许您模拟测试。在构造函数中,我检查参数是否为null(这是生产代码中的情况),如果是,则默认为Singleton实例。我正在写我的答案,但我不能告诉其他任何事情:)你所说的“为什么不简单地以这种方式共享缓存,而不是增加单例数”是什么意思。如何共享缓存?您的意思是,将其作为参数传递吗?@Martijn-您希望引用单个实例,因此可以使用单例缓存,或者使用配置为通过构造函数注入单个实例的DI框架。为了支持单元测试,我有时为单例创建了一个接口,并注入了该接口的一个实例。这允许您模拟测试。在构造函数中,我检查参数是否为null(这是生产代码中的情况),如果是,则默认为Singleton实例