【问题标题】:Is Repository Singleton or Static or None of these?存储库是单例的还是静态的还是都不是?
【发布时间】:2011-11-19 18:02:13
【问题描述】:

我有一个 ASP.NET 网站,它使用域驱动设计并使用存储库进行数据库操作。
我想知道单例存储库和静态存储库以及简单存储库类的优缺点是什么,每次访问都会新增?
如果有人可以比较并指导我使用其中哪一个,我将不胜感激。

【问题讨论】:

    标签: asp.net database-design architecture domain-driven-design


    【解决方案1】:

    静态和单例不是存储库模式的好解决方案。如果您的应用程序将来会使用 2 个或更多存储库怎么办?

    IMO 最好的解决方案是使用依赖注入容器并将您的 IRepository 接口注入需要它的类中。

    我建议你阅读一本关于领域驱动设计的好书和一本关于依赖注入的好书(比如 Mark Seeman 的 Dependency Injection in .NET)。


    使用单例和静态类,您的应用程序将无法扩展

    您有两个单例存储库:

    class Repository<TEntity> {
    
      static Repository<TEntity> Instance { get { ... /*using sql server*/ } }
    }
    
    class Repository2<TEntity> {
    
      static Repository2<TEntity> Instance { get { ... /*using WCF or XML or any else */ } }
    }
    

    使用它们的服务必须具有对其中之一或两者的静态引用:

    class OrderService {
    
        public void Save(Order order) { Repository<Order>.Instance.Insert(order); }
    }
    

    如果存储库是静态引用的,您如何使用 Repository2 保存您的订单

    更好的解决方案是使用 DI:

    interface IRepository<TEntity> { ... }
    
    class SqlRepository<TEntity> : IRepository<TEntity> { ....}
    
    class OrderService {
        private readonly IRepository<TEntity> _repo;
    
        public OrderService(IRepository<TEntity> repo) { _repo = repo; }
    
        public void Save(Order order) { repo.Insert(order); }
    }
    

    【讨论】:

    • 我将使每个存储库成为单例。有什么问题吗?
    【解决方案2】:

    不要使用静态或单例存储库,因为:

    • 影响可测试性,单元测试时不能mock。

    • 它会影响可扩展性,你不能做一个以上的具体实现,你不能在不重新编译的情况下替换行为。

    • 它在生命周期管理方面影响可扩展性,insetead依赖依赖注入框架来注入依赖和管理生命周期。

    • 它影响可维护性,它迫使依赖于具体实现而不是抽象。

    底线:不要使用静态或单例存储库

    而是在您的域模型项目中创建存储库接口,并在具体的数据访问项目中实现这些接口,并使用依赖注入框架。

    【讨论】:

      【解决方案3】:

      SOLID 没有单例存储库的两个原因:

      • 存储库的使用者将耦合到存储库实现。这将对可扩展性和可测试性产生负面影响。这是DIP 违规。依赖抽象,而不是具体。

      • 存储库实现必须违反SRP,因为它很可能最终会管理 ORM 会话、数据库连接和潜在的事务。它还必须保证线程安全,因为它可能可以从多个线程中使用。相反,应该将数据库连接(ORM Session)注入到存储库实现中,以便使用代码可以将多个存储库调用安排到事务中。

      这两个问题的可能解决方案是Constructor Injection

      【讨论】:

      • 单身人士如何与消费者结合?消费者不会知道它是否是一个新创建的实例
      【解决方案4】:

      我个人非常不同意之前的回答。

      我开发了多个网站(其中一个网站每月浏览量达 700 万次),我的静态存储库从未遇到过任何问题。

      我的静态存储库实现非常简单,只包含对象提供者作为属性。一个存储库可以包含您需要的任意数量的提供程序。

      然后,提供者负责管理数据库连接和事务。使用 TransactionScope,消费者可以管理事务或将其交给提供者。

      每个提供者都是使用单例模式开发的。

      这样,我可以通过简单地调用来获取我的对象:

      var myObj = MyRepository.MyProvider.GetMyObject(id);
      

      在任何时候,在我的应用程序的每个 Web 池中,每种类型都只有一个存储库和一个提供者。根据您网站上同时拥有多少用户,您可以设置多个网络池(但大多数情况下,一个就足够了)。

      我看不到我的存储库/提供者消费者与我的存储库的耦合位置。事实上,我的提供者的实现完全是从它们中抽象出来的。当然,我的存储库返回的所有提供程序都是接口,我可以随时轻松更改它们的实现并将我的新 dll 推送到 Web 服务器上。如果我想创建一个具有相同界面的全新提供程序,我只需在一个地方进行更改:我的存储库。

      这样,无需添加依赖注入或创建自己的ControllerFactory(用于MVC procjects)。

      而且您仍然拥有控制器中干净代码的优势。每次请求页面时,您还将节省大量的存储库创建和销毁(通常在 ControllerFactory 中使用反射)。

      如果您正在寻找可扩展的解决方案(如果您确实需要它,但大多数情况下这并不是真正的问题),与依赖注入相比,我开发存储库的方式绝不会成为问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-27
        • 2016-08-31
        • 1970-01-01
        • 1970-01-01
        • 2011-06-11
        • 1970-01-01
        相关资源
        最近更新 更多