2011-05-26 25 views
7

Estoy creando una clase base de repositorio con Entity Framework donde heredarán todos los repositorios de Entidades. Quiero inyectar el DatabaseContext en la clase base usando Dependency Injection usando Ninject. Creo que la inyección de Constructor es la correcta, pero al hacer esto con Constructor Injection en la clase derivada I tendré que pasar el parámetro al constructor en la clase base y no lo quiero. Por lo tanto, ¿una Inyección Setter es más apropiada?Inyección de dependencia de constructor en la clase base

Aquí está mi código:

public abstract class BaseRepository<TEntity> : IDisposable 
    where TEntity : class 
{ 
    private readonly DatabaseContext _databaseContext; 

    protected BaseRepository(DatabaseContext databaseContext) 
    { 
     this._databaseContext = databaseContext; 
    } 
} 

Usando Constructor de inyección en el ejemplo anterior, en mi clase derivada que se debe a pasar DatabaseContext objeto de clase base, no me gusta hacer esto con todo mi clase derivada:

public class UsuarioRepository : BaseRepository<IUsuario>, 
    IUsuarioRepository 
{ 
    public UsuarioRepository(DatabaseContext databaseContext) 
     : base(databaseContext) 
    { 
    } 
} 

Setter inyección en lugar de Constructor de inyección es una buena manera de resolver esto? ¿Cuál es la mejor manera?

Actualización:

usar la inyección de Setter de mi clase derivada no tener constructores:

public class UsuarioRepository : BaseRepository<IUsuario>, IUsuarioRepository 
{ 
} 

mi contexto es único en toda la aplicación. No necesito una clase derivada para pasar el objeto de contexto, pero me gusta inyectarlo en la clase base para usar simulaciones para pruebas en el futuro.

que resolver el problema:

Lo siento, estoy confundiendo con la pregunta, pero yo soy la solución de mi problema de la construcción de una fábrica:

public abstract class BaseRepository<TEntity> : IBaseRepository<TEntity> 
    where TEntity : class 
{ 
    private readonly ContextFactory _contextFactory = new ContextFactory(); 

    protected DatabaseContext CurrentContext 
    { 
     get 
     { 
      return this._contextFactory.GetCurrentContext(); 
     } 
    } 
} 

Y mi clase derivada se parecerá que:

public class UsuarioRepository : BaseRepository<IUsuario>, IUsuarioRepository 
{ 
} 

Y mi fábrica así:

public class ContextFactory 
{ 
    public DatabaseContext GetCurrentContext() 
    { 
     return new DatabaseContext(); 
    } 
} 
+0

No entiendo muy bien su pregunta. ¿Por qué no le gusta pasar el DatabaseContext a la clase base a través del constructor? ¿Estás tratando de evitar tener que inyectar el contexto a la clase derivada? No veo nada de malo con el código anterior, así que no estoy seguro de qué "problema" estás tratando de resolver específicamente. – fearofawhackplanet

+0

Mi clase derivada tiene un parámetro para la clase base. Usando Setter Injection esto no ocurrirá, quiero saber si usar setter injection en esa situación es una buena manera. –

+0

¿Qué pasa con pasar un parámetro a la clase base? – Phil

Respuesta

3

No creo que haya una "mejor manera".

La inyección de constructor y setter no son exactamente equivalentes, ya que la inyección setter le proporciona un poco más de flexibilidad. Aquí es cómo elijo entre los dos:

Digamos que creas un objeto A, y A necesita un objeto B para funcionar. La pregunta que debe hacerse es: ¿es posible que A exista/se cree una instancia sin tener una B asociada? ¿Es un estado válido para el objeto A no tener un B? A veces no tiene sentido que A tenga siempre un nulo B, entonces la inyección del constructor es la mejor solución. Si, está bien que B sea asignado a A más adelante y no necesariamente en el momento de la construcción, entonces continúe con la inyección del colocador. Todo esto depende del dominio que está tratando de modelar y las respuestas cambiarán de una situación a otra.

+0

La pregunta es, no me gusta hacer ruido mi parámetro de paso de clase derivado a los constructores de la clase base. –

17

La Inyección de Propiedades implica que la dependencia es opcional, mientras que la Inyección de Constructor implica que se requiere la dependencia. Elija un patrón en consecuencia.

En más del 95% de los casos, la inyección del constructor es el patrón correcto. ¿Qué pasa con eso no te gusta?

+4

No me gusta pasar un parámetro a la clase base en mi clase derivada, con setter injection esto no ocurrirá. –

+2

@Acaz preferencias personales a un lado, la inyección de constructor es realmente la única solución adecuada para su escenario. –

+4

@Acaz El problema es que si 'BaseRepository ' requiere una instancia de 'DatabaseContext' para funcionar, es una dependencia y no debe permitir que una instancia de la clase base se cree una instancia con un estado no válido. Los constructores se usan para crear una instancia de un tipo que debería ser utilizable.El uso de la configuración de inyección solo introduce la necesidad de que el desarrollador sepa con precisión que necesita establecer 'DatabaseContext' como un paso adicional en la inicialización de tipo. No idealmente lo mejor para el desarrollador. Simple, si es una dependencia, use la inyección de constructor. –

0

Todas las tres formas 1. Contstructor, 2. Setter y 3. Interface Injection tiene sus ventajas y desventajas, depende de la situación cuál usar. Si yo estuviera en tu lugar, me habría ido con setter, aunque la interfaz también puede ser una buena opción.

Solicitud a pasar por este artículo http://www.devx.com/dotnet/Article/34066

3

Realmente, no veo ningún problema con pasar un parámetro a una clase base. Pero si eso es un requisito absoluto, siempre se puede hacer esto:

public abstract class BaseRepository<TEntity> : IDisposable 
    where TEntity : class 
{ 
    protected BaseRepository() 
    { 
    } 

    protected abstract DatabaseContext GetContext(); 
} 

Ahora sus clases derivadas pueden tener este aspecto:

public class UsuarioRepository : BaseRepository<IUsuario>, 
    IUsuarioRepository 
{ 
    private DatabaseContext _databaseContext; 

    public UsuarioRepository(DatabaseContext databaseContext) 
    { 
     _databaseContext = databaseContext; 
    } 

    protected override DatabaseContext GetContext() 
    { 
     return _databaseContext; 
    } 
} 

Ahora usted puede tener la inyección de constructor sin pasar un parámetro al constructor base . Pero es realmente lo mismo.

Honestamente, no me gusta la idea de la inyección setter, porque parece que el DatabaseContext es una dependencia requerida. Para las dependencias requeridas, haga la inyección del constructor. Si fuera opcional, entonces, por supuesto, adelante y realice la inyección del colocador.

EDIT:

Debido a nuestra larga conversación en los comentarios, tengo una comprensión mucho mejor de lo que estamos tratando de lograr.

Si desea desacoplar las clases derivadas de DatabaseContext, es mejor que lo diseñe de forma diferente. Es difícil desacoplar una clase derivada de las dependencias de su clase base, y si cree que deberían estar desacopladas, entonces tendrá un mejor diseño sin usar herencia en absoluto.

public class BaseRepository<TEntity> : IDisposable 
    where TEntity : class 
{ 
    public BaseRepository(DatabaseContext context) 
    { 
    } 
} 

Ahora sus clases derivadas (que no se derivarían más) sería el siguiente:

public class UsuarioRepository : IUsuarioRepository 
{ 
    public UsuarioRepository(BaseRepository<IUsario> repository) 
    { 
    } 

    // Implement other methods here 
} 

Ahora usted puede tener su una clase base que utiliza el DatabaseContext, y sus clases derivadas no son una depende más de eso.

+0

¡Mi contexto es SOLO UNA de todas las aplicaciones! No necesito una clase derivada para pasar el contexto. –

+0

@Acaz Ver ediciones. – Phil

+0

@Phil ¿Por qué pasaré el parámetro a mi constructor de clase base si ese parámetro SÓLO ES UNO en todas las aplicaciones? ¿Por qué no pasar directamente a la clase base? –

Cuestiones relacionadas