如何在存储库模式中为同一接口使用两个数据存储?

Posted

技术标签:

【中文标题】如何在存储库模式中为同一接口使用两个数据存储?【英文标题】:How to use two data stores for same interface in repository pattern? 【发布时间】:2014-03-12 19:04:22 【问题描述】:

从 TDD 的角度来看,我清楚地了解什么是存储库模式及其重要性。我也明白,为应用程序切换底层数据存储是多么容易,因为存储库充当数据访问逻辑的窗口。

我没有得到的是如何同时支持多个数据存储。这是一个示例,假设我已经定义了一个存储库 IPersonRepository,它有两个实现,并且要求是读取 XML 文件并存储到 SQL 数据库中,反之亦然。

数据访问层

public interface IPersonRepository  
  
    Person GetPersonById(int id);  
  

public class PersonRepositorySQL : IPersonRepository  
  
    public Person GetPersonById(int id)  
      
        // get person from sql db (using ado.net)  
      
  

public class PersonRepositoryXML : IPersonRepository  
  
    public Person GetPersonById(int id)  
      
        // get person from xml file  
      
  

业务逻辑层

public PersonService   
  
    private IPersonRepository personRepository;  

    public PersonService(IPersonRepository personRepository)  
      
        this.personRepository = personRepository;  
      

    public Person GetPersonById(int id)  
      
        personRepository.GetPersonById(id);  
      
  

问题(按重要性排序):

    这是否意味着我每次都必须通过分别传递 PersonRepositorySQL 和 PersonRepositoryXML 从 db 和 xml 读取数据来实例化两个 PersonService 对象? 为了执行上述操作,我必须在上层(主要是演示文稿)中添加对存储库的引用?如何避免这种情况? DAL 是保存存储库的好地方吗? 是否可以将 BLL 类命名为服务,例如:PersonService?

我意识到这篇文章已经变得很长,但我想把所有引起混淆的地方都记在心里。

-- NV

【问题讨论】:

【参考方案1】:

这是否意味着我每次都必须实例化两个 PersonService 对象,以便通过分别传递 PersonRepositorySQL 和 PersonRepositoryXML 从 db 和 xml 读取数据?

不,但您正朝着正确的方向前进。我会将两个存储库都注入到服务中(两个构造函数参数)并编写两个服务方法,一个以一种方式移动数据,另一个以另一种方式移动数据。

连接两个存储库应该是服务的责任,而不是客户端的责任。

然后使用 IoC 容器来设置服务实例并将其提供给客户端,绝对不建议到处使用 New Services()。您需要查找最适合您使用的任何演示技术的 IoC 工具/方法。

对于上述操作,我必须在上层(主要是演示文稿)添加对存储库的引用?如何避免这种情况?

这对于展示来说没问题,因为它需要知道将什么注入服务实例,展示是您需要直接引用具体 DAL 类的唯一地方,并且仅出于这个原因。

当我不太确定时,我发现谷歌搜索 VS 分层架构项目结构(或类似项目结构)帮助我回想起来。

DAL 是保存存储库的好地方吗?

这就是他们应该在的地方。您的 DAL 通常适用于涉及硬件的所有内容,例如文件、dbs、webapis。

可以将 BLL 类命名为 Service ex: PersonService 吗?

当然。它简短、甜美,告诉人们(和其他开发人员)它是什么(服务)以及它的职责是什么(人)

【讨论】:

【参考方案2】:

只是为了解决问题 #1:您可以实例化一个服务并将Composite 传递给它,而不是实例化两个服务。为此,您需要一个 CompositeRepositoryFactory 类型来创建适当的 Composite。请注意,一个

更多关于 Composite 和您的特殊情况:

它允许您在客户端维护对原始接口的引用时链接多个实现。 允许您链接同一接口的多个实现。这样,实现级联方法调用,允许更丰富的逻辑。另一方面,客户端维护所需的依赖关系:仅对接口本身。 复合模式有利于 SRP 原则:如果你的类太广泛并且接口很大,你将无法装饰它,因为: 很难精确地实现装饰(因为类做了太多)。 在下图中:客户端引用了CompositeComponent(通过IComponent 引用变量)。 CompositeComponent 引用了另一个 IComponent 实现(例如 ConcreteComponent),它在Something() 中拥有自己的一些逻辑,然后作为该逻辑的一部分——它调用ConcreteComponent.Something()。这样,对CompositeComponent.Something() 的初始调用将级联到ConcreteComponent

我还创建了一个关于上图如何应用于您的案例的快速图表:您的客户端代码将继续使用PersonService,但是您无需直接传递一些IPersonRepository 实现,而是首先转到PersonCompositeRepositoryFactory。解析根端唯一需要的更改是使用PersonCompositeRepositoryFactory

【讨论】:

以上是关于如何在存储库模式中为同一接口使用两个数据存储?的主要内容,如果未能解决你的问题,请参考以下文章

如何处理存储库模式中的异构数据源?

在使用 IdentityDbContext 的情况下,如何在 ASP.NET Core MVC 中使用存储库模式?

存储库模式缺少啥?你如何在现实世界中使用它?

两个具有相同数据存储库的 Prometheus

如何在两个不同的片段中使用存储库数据

存储库设计模式