这是对单例的误用吗?

本文关键字:单例 | 更新日期: 2023-09-27 18:04:37

我已经阅读了所有关于单例模式的内容,以及它们如何在被滥用时构成反模式的威胁。所以我想听听别人的意见,看看这是不是对模式的误用。

实际上我有5个存储库。它们所做的就是存储数据。实际上,它们存储的所有数据都是密切相关的,我只为它们创建了5个不同的存储库,以便这些类简短且易于挑选。我知道,如果我把这些存储库都变成单例,我就可以对任何可维护的单元测试说再见了;然而;我有这样的想法,我可以让每个存储库成为一个普通的类,然后创建一个单例,它只存储每个存储库的一个副本。

通过这种方式,我可以满足每个程序实例只有一个数据中心位置的要求,但我也可以对每个存储库进行单元测试,包括它需要执行的一些操作。

这是对单例的误用吗?

当然,您可能能够对存储库进行单元测试,但是对依赖于这些存储库的所有其他代码进行单元测试肯定会很困难。单例通过直接访问分散在整个代码库中的方式,将调用代码与唯一实现耦合。即使你的数据真的只有一个副本,比如某种内存数据库,也没有理由让其他层知道这一点。

而且,通过"使它们成为一个简单的类"(我想你的意思是,通过公开一个公共构造函数?),你破坏了单例的全部意义,即没有其他代码可以实例化不同实例的概念。

如果存储库是某个类的依赖项,那么只需使用构造函数注入传递它们,使您的测试更容易。这将允许您在测试来自域层的类时轻松地模拟每个存储库。

什么构成了单例的误用(或者它的总体有用性),是那些没有明确答案的宗教争论之一。

然而,您发现了单例模式的一个主要缺点,那就是它使单元测试复杂化。更糟糕的是,它通常会降低代码的整体可维护性。

考虑这个可能的替换;

   public interface IRepositoryContainer
   {
      IRepository GetRepository<T>() where T : IRepository;
   }
   public partial class App : Application, IRepositoryContainer
   {
      private List<IRepository> repositories =
         new List<IRepository>() { new MyRespository() };
      public IRepository GetRepository<T>() 
         where T : IRepository
      {
         return repositories.Where(t => t is T).SingleOrDefault();
      }

那么在此之前你应该调用一个单例,而不是…

     IRepository repo = (Application.Current as IRepositoryContainer).GetRepository<MyRespository>();

只是一个想法,但是已经只有一个实例的应用程序,接口可以帮助你解决这个问题。

(是的,上面的示例代码是wpf,但主体应该适用)