如何在存储库模式中为同一接口使用两个数据存储?
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
【讨论】:
以上是关于如何在存储库模式中为同一接口使用两个数据存储?的主要内容,如果未能解决你的问题,请参考以下文章