2009-11-03 85 views
4

我在写一个使用DDD技术的应用程序。这是我第一次尝试DDD项目。这也是我的第一个绿地项目,我是唯一的开发者。我充实了域模型和用户界面。现在我开始持久层。像往常一样,我从单元测试开始。我在数据持久层中需要多少抽象级别?

[Test] 
public void ShouldAddEmployerToCollection() 
{ 
    var employerRepository = new EmployerRepository(); 
    var employer = _mockery.NewMock<Employer>(); 

    employerRepository.Add(employer); 
    _mockery.VerifyAllExpectationsHaveBeenMet(); 
} 

正如你所看到的,我没有写任何对Add()函数的期望。我得到了这一点,并意识到我还没有解决特定的数据库供应商。实际上,我甚至不确定它需要一个数据库引擎。平面文件或xml可能同样合理。所以我不知道我的下一步应该是什么。

我应该添加一个抽象层......说一个DataStore接口或寻找一个已经为我工作的现有库吗?如果可以的话,我想避免将程序绑定到特定的数据库技术上。

回答

8

根据您的要求,您真正需要的唯一抽象是具有基本CRUD语义的存储库接口,以便您的客户端代码和协作对象仅处理IEmployerRepository对象而不处理具体存储库。你有几个选择去做:

1)没有更多的抽象。只是构建您的顶级应用程序的具体信息库在你需要它:

IEmployeeRepository repository = new StubEmployeeRepository(); 
IEmployee   employee = repository.GetEmployee(id); 

改变,在一百万的地方会变老,所以这种技术只适用于非常小的项目确实可行。

2)创建仓库工厂在应用程序中使用:

IEmployeeRepository repository = repositoryFactory<IEmployee>.CreateRepository(); 
IEmployee   employee = repository.GetEmployee(id); 

你可能仓库工厂传递到将使用它的类,或者您可以创建一个应用程序级的静态变量来保存它(这是一个单身人士,这是不幸的,但相当有限)。

3)使用依赖注入容器(本质上是通用的工厂和配置机制):

// A lot of DI containers use this 'Resolve' format. 
IEmployeeRepository repository = container.Resolve<IEmployee>(); 
IEmployee   employee = repository.GetEmployee(id); 

如果你还没有使用DI容器之前,也有很多很好的问题及答案关于他们在这里(如Which C#/.NET Dependency Injection frameworks are worth looking into?Data access, unit testing, dependency injection),你一定要读马丁福勒的Inversion of Control Containers and the Dependency Injection pattern)。

+0

针对存储库接口的+1 – 2009-11-03 14:37:12

+0

EmployerRepository实际上实现了IEmployerRepository接口,该接口公开CRUD操作。你是否建议我应该实现数据库感知的具体类,如SQLServerEmployerRepository,OracleEmployerRepository,FlatFileEmployerRepository等,直到我决定数据库技术? – 2009-11-03 14:49:37

+0

在这种情况下,我试图TDD我的方式来实施IEmployerRepository,但我想我不能这样做,除非我要在存储库下面添加另一个抽象级别(这似乎没有添加任何有用的东西),编写和测试几个数据库相关的实现,或者选择一个数据库并坚持使用它。 – 2009-11-03 15:08:00

1

在某些时候,您将不得不打电话了解您的存储库将如何处理数据。当你开始你的项目时,最好尽可能保持简单,并且在必要时只添加抽象层。在这个阶段简单定义你的仓库/ DAO可能就足够了。

通常,存储库/存储库/ DAO应该知道您决定使用哪个数据库或ORM的实现细节。我期望这就是你在DDD中使用仓库的原因。通过这种方式,您的测试可以模拟存储库,并且可以不执行实现。

0

有一件事我已经与持久层发现的是,以确保有一个地方,你可以开始做抽象。如果数据库增长,则可能需要开始实施分片,除非已经有可用的抽象层,否则稍后添加抽取层可能会很困难。

0

我相信你不应该为了单元测试的目的在存储库类下面增加另一层,特别是如果你没有选择你的持久化技术。我不认为你可以创建一个比“repository.GetEmployee(id)”更细粒度的接口,而不会公开有关持久化方法的细节。

如果你真的在考虑使用平面文本或XML文件,我相信最好的选择是坚持存储库接口抽象。但是如果你决定使用数据库,而你对供应商不确定,那么一个ORM工具可能就是要走的路。