Patrón de repositorio - ¿Por qué exactamente necesitamos Interfaces?


He leído de Internet Tengo este puntos que dice Interfaces se utiliza para esto

  • Use métodos TDD
  • Reemplazar motor de persistencia

Pero no soy capaz de entender cómo interfaz será útil a este punto Replace persistance engine. consideremos que estoy creando un repositorio básico (sin genéricos) para EmployeeRepository

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

Entonces, ¿cómo entran en escena las interfaces?

Y si supongamos que he creado una interfaz, ¿por qué se utiliza upcasting ? por ejemplo,

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

Por favor explíqueme con precisión y también otra utilidad de la Interfaz con respecto al Patrón del Repositorio.

Author: Meson, 2012-05-16

2 answers

Entonces, ¿cómo entran en escena las interfaces ?

Así:

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

Y entonces usted podría tener tantas implementaciones como desee:

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

Como puede ver, no es realmente importante cómo implementamos el repositorio. Lo importante es que todos los repositorios e implementaciones respeten el contrato definido (interfaz) y todos posean un método GetAll que devuelva una lista de empleados.

Y luego tendrás un controlador que usa esto interfaz.

public class EmployeesController: Controller
{
    private readonly IEmployeeRepository _repository;
    public EmployeesController(IEmployeeRepository repository)
    {
        _repository = repository;
    }

    public ActionResult Index()
    {
        var employees = _repository.GetAll();
        return View(employees);
    }   
}

Vea cómo el controlador ya no depende de una implementación específica del repositorio? Todo lo que necesita saber es que esta implementación respeta el contrato. Ahora todo lo que necesita hacer es configurar su marco de inyección de dependencias favorito para usar la implementación que desee.

Aquí hay un ejemplo de cómo se hace esto con Ninject:

  1. Instala el Ninject .MVC3 NuGet
  2. En el código generado ~/App_Start/NinjectWebCommon.cs simplemente decide utilizar la implementación de HA con una sola línea de código:

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

De esta manera ya no necesita hacer ninguna instanciación manual de esas clases de repositorio y preocuparse por upcasting o lo que sea. Es el marco de inyección de dependencias el que las gestiona por usted y se encargará de inyectar la implementación definida en el constructor del controlador.

Y simplemente modificando esta configuración, podría cambiar su tecnología de acceso a datos sin tocar un una sola línea de código en su controlador. Así es como las pruebas unitarias en aislamiento también entran en juego. Dado que el código del controlador ahora está débilmente acoplado al repositorio (gracias a la interfaz que introdujimos), todo lo que necesita hacer en la prueba unitaria es proporcionar alguna implementación simulada en el repositorio que le permita definir su comportamiento. Esto le da la posibilidad de probar unitariamente la acción del controlador de índice sin ninguna dependencia de una base de datos o lo que sea. Aislamiento completo.

I también le invitamos a revisar los siguientes artículos {[25] } sobre TDD y DI en ASP.NET MVC.

 72
Author: Darin Dimitrov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-16 10:09:23

Usted expondría su repositorio como una interfaz:

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

Esto le permitiría tener muchas implementaciones diferentes de la interfaz, como la predeterminada:

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

O una prueba:

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

Su código que consume el repositorio solo está interesado en usar la interfaz:

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

La salsa secreta es la fábrica, u otro mecanismo por el cual resolver la interfaz en un tipo utilizable (un marco de inyección de dependencias como Ninject, o el Castillo Windsor cumplirá este papel).

El punto es, el código consumidor no se preocupa por la implementación, solo el contrato (la interfaz). Esto le permite intercambiar implementaciones con fines de prueba muy fácilmente y promueve el acoplamiento suelto.

Solo para aclarar, no hay ningún vínculo entre el uso de interfaces y el patrón de repositorio específicamente, es solo otro patrón que puede hacer uso de ellos.

 14
Author: Adam Houldsworth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-16 10:03:18