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

本文关键字:接口 我们 为什么 模式 存储 | 更新日期: 2023-09-27 18:34:23

我从互联网上读到了这一点,它说接口用于此

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

但是我无法理解界面将如何用到这一点Replace persistance engine.让我们考虑一下我正在为EmployeeRepository创建一个基本的(没有泛型(存储库

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

那么界面是如何出现的呢?

如果假设我创建了一个为什么使用向上转换的接口?

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

请准确地解释我以及有关存储库模式的接口的其他有用性。

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

那么界面是如何进入图片的呢?

喜欢这个:

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);
    }   
}

了解控制器如何不再依赖于存储库的特定实现?它需要知道的是此实现是否遵守合同。现在,您需要做的就是配置您喜欢的依赖注入框架以使用您想要的实现。

以下是如何使用 Ninject 完成此操作的示例:

  1. 安装 Ninject.MVC3 NuGet
  2. 在生成的~/App_Start/NinjectWebCommon.cs代码中,只需决定将 EF 实现与一行代码一起使用:

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

这样,您不再需要对这些存储库类进行任何手动实例化,也不必担心向上转换或其他什么。它是为您管理它们的依赖注入框架,并将负责将定义的实现注入控制器构造函数。

通过简单地修改此配置,您可以切换数据访问技术,而无需接触控制器中的任何一行代码。这就是孤立的单元测试也发挥作用的方式。由于您的控制器代码现在与存储库弱耦合(由于我们引入的接口(,因此您在单元测试中需要做的就是在存储库上提供一些模拟实现,以允许您定义其行为。这使您可以对索引控制器操作进行单元测试,而无需依赖数据库或其他任何内容。完全隔离。

我还邀请您查看以下有关 MVC 中的 TDD 和 DI ASP.NET 文章。

您可以将存储库公开为接口:

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

这将允许您拥有许多不同的接口实现,例如默认的:

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

或测试:

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

然后,使用存储库的代码只对使用该接口感兴趣:

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

秘密武器是工厂,或者另一种将接口解析为可用类型的机制(依赖注入框架,如Ninject或Castle Windsor将履行此角色(。

关键是,消费代码不关心实现,只关心合约(接口(。这使您可以非常轻松地交换用于测试目的的实现,并促进松散耦合。

澄清一下,接口的使用与存储库模式之间没有联系,它只是另一种可以使用它们的模式。