存储库模式 – 为什么我们需要接口?

我已经从互联网上读到,我得到了这个说Interfaces是用于这个的点

  • 使用TDD方法
  • 更换持久性引擎

但我无法理解接口将如何有用Replace persistance engine 。 让我们考虑为EmployeeRepository创build一个基本的(没有generics)仓库

 public class EmployeeRepository { public employee[] GetAll() { //here I'll return from dbContext or ObjectContex class } } 

那么接口如何进入画面呢?

如果我想创build一个接口,为什么使用upcasting? 例如

  IEmployee emp = new EmployeeRepository() ; vs EmployeeRepository emp = new EmployeeRepository(); 

请详细解释我,还有关于Repository Pattern的其他有用的接口。

那么接口如何进入画面呢?

喜欢这个:

 public interface IEmployeeRepository { Employee[] GetAll(); } 

然后你可以有很多的实现,只要你喜欢:

 public class EmployeeRepositoryEF: IEmployeeRepository { public Employee[] GetAll() { //here you will return employees after querying your EF DbContext } } public class EmployeeRepositoryXML: IEmployeeRepository { public Employee[] GetAll() { //here you will return employees after querying an XML file } } public class EmployeeRepositoryWCF: IEmployeeRepository { public Employee[] GetAll() { //here you will return employees after querying some remote WCF service } } and so on ... you could have as many implementation as you like 

正如你所看到的,我们如何实现仓库并不重要。 重要的是,所有的存储库和实现都遵守已定义的合同(接口),并且都拥有一个返回员工列表的GetAll方法。

然后你将有一个使用这个接口的控制器。

 public class EmployeesController: Controller { private readonly IEmployeeRepository _repository; public EmployeesController(IEmployeeRepository repository) { _repository = repository; } public ActionResult Index() { var employees = _repository.GetAll(); return View(employees); } } 

看看控制器不再依赖于存储库的特定实现吗? 所有它需要知道的是这个实现尊重合同。 现在你所需要做的就是configuration你喜欢的dependency injection框架来使用你想要的实现。

下面是一个如何用Ninject完成的例子:

  1. 安装Ninject.MVC3 NuGet
  2. 在生成的~/App_Start/NinjectWebCommon.cs代码中,您只需决定使用~/App_Start/NinjectWebCommon.cs代码就可以使用EF实现:

     private static void RegisterServices(IKernel kernel) { kernel.Bind<IEmployeeRepository>().To<EmployeeRepositoryEF>(); } 

这样你不再需要对这些存储库类进行任何手动实例化,并担心向上转换或其他任何事情。 它是为您pipe理它们的dependency injection框架,并负责将定义的实现注入到控制器构造函数中。

通过简单的修改这个configuration,你就可以切换你的数据访问技术,而不需要触摸你的控制器中的一行代码。 这样一来unit testing的方式也就起作用了。 由于您的控制器代码现在与存储库弱耦合(感谢我们介绍的接口),所以您在unit testing中需要做的是在存储库上提供一些模拟实现,从而允许您定义其行为。 这使您可以unit testing索引控制器的动作,而不依赖于数据库或其他任何东西。 完全隔离。

我还邀请你去看看关于ASP.NET MVC中的TDD和DI的以下文章 。

你会把你的版本库作为一个接口公开:

 public interface IEmployeeRepository { List<Employee> GetAll(); } 

这将允许你有许多不同的接口实现 ,比如默认的接口:

 public class EmployeeRepository : IEmployeeRepository { public List<Employee> GetAll() { // Return from db. } } 

或者是testing一:

 public class TestEmployeeRepository : IEmployeeRepository { public List<Employee> GetAll() { // Stub some dummy data. } } 

您的代码使用库只对使用接口感兴趣:

 IEmployeeRepository myRepo = MyRepositoryFactory.Get<IEmployeeRepository>(); 

秘密就是工厂,或者将接口parsing成可用types的另一种机制(像Ninject这样的dependency injection框架,或者温莎城堡就可以实现这个angular色)。

重点是, 消费代码不关心实现 ,只有合同 (接口)。 这使您可以非常容易地将testing用途换出来,并促进松耦合。

只是为了澄清,接口的使用和存储库模式之间没有任何联系,这只是另一种可以利用它们的模式。