2012-05-16 11 views
33

He leído desde Internet Tengo este puntos que dice Interfaces Para ello se utiliza métodosPatrón de repositorio: ¿por qué necesitamos interfaces exactamente?

  • Uso TDD
  • Reemplazar motor de persistencia

Pero no soy capaz de entender cómo interfaz ser útil en 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 las interfaces entran en la imagen?

y si supongo que he creado una interfaz ¿por qué se utiliza la conversión ascendente? por ejemplo para

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

favor explicar mi manera precisa y también otra UTILIDAD de la interfaz con respecto a la del patrón Repositorio.

Respuesta

69

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

De esta manera:

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 se puede ver que no es realmente importante cómo ponemos en práctica el repositorio.Lo importante es que todos los repositorios y las implementaciones respetan el contrato definido (interfaz) y todos poseen un método GetAll que devuelve una lista de empleados.

Y luego tendrá un controlador que utiliza esta 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. Instalar el Ninject.MVC3 NuGet
  2. En el ~/App_Start/NinjectWebCommon.cs código generado simplemente decide utilizar la aplicación EF con una sola línea de código:

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

de esta manera ya no es necesario hacer ningún ejemplificaciones de manuales esas clases de repositorio y se preocupan por upcasting o lo que sea. Es el marco de inyección de dependencias que los administra por usted y se encargará de inyectar la implementación definida en el constructor del controlador.

Y simplemente modificando esta configuración, puede cambiar su tecnología de acceso a datos sin tocar una sola línea de código en su controlador. Así es como entran en juego las pruebas unitarias en aislamiento. Dado que su código de controlador ahora está débilmente acoplado al repositorio (gracias a la interfaz que presentamos), 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 la unidad de la acción del controlador de índice sin ninguna dependencia en una base de datos o lo que sea. Aislamiento completo

También lo invito a que compruebe el following articles sobre TDD y DI en ASP.NET MVC.

+1

maravillosa respuesta, cada explicación vale ... ahora lo entiendo cómo funcionan las cosas ... gracias, no puedo marcar esta respuesta como aceptada ya que mis puntos están por debajo de 15, tan pronto como gane lo aceptaré como respuesta. – Meson

+0

gracias por ese artículo ... y supongamos que si configuro 'EmployeeRepositoryEF' en mi marco de inyección de dependencias, mi controlador consumirá este' EmployeeRepositoryEF', pero ¿y si quiero consumir 2 implementaciones en el mismo controlador ... si esta pregunta es estúpida? lo siento mucho ... – Meson

+2

En el ejemplo I provider, el controlador espera una instancia 'IEmployeeRepository' en su constructor. Solo se puede aprobar una implementación única. Por otro lado, podría tener otro controlador que pueda necesitar una implementación diferente de la interfaz. Eso es perfectamente posible. Solo necesita configurar su infraestructura DI para que inyecte ImplementationA en ControllerA e ImplementationB en ControllerB. La sintaxis, por supuesto, variará entre los diferentes marcos DI. –

14

Se podría exponer a su repositorio como una interfaz:

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

Esto permitiría que usted tenga muchos diferentes implementaciones de la interfaz, tales como la opción por defecto:

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

O una prueba uno:

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

Tu código consumir el repositorio es entonces sólo está interesado en el uso de la interfaz:

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

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

El punto es, el código que consume no se preocupa por la aplicación, sólo el contrato (la interfaz). Esto le permite intercambiar implementaciones con fines de prueba con mucha facilidad y promueve el acoplamiento libre.

Solo para aclarar, no existe un 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.

+0

gracias por su respuesta rápida ... y una pregunta más Q por qué upcasting 'IEmployee emp = new EmployeeRepository();' contra 'EmployeeRepository emp = new EmployeeRepository();' ?? – Meson

Cuestiones relacionadas