2011-08-26 18 views
8

Según los principios SOLIDOS, una clase no puede depender de otras clases, las dependencias deben ser inyectadas. Es muy sencillo:Inversión de dependencia. Creación de objetos

class Foo 
{ 
    public Foo(IBar bar) 
    { 
     this.bar = bar; 
    } 

    private IBar bar; 
} 

interface IBar 
{ 
} 

class Bar: IBar 
{ 
} 

Pero lo que si quiero que mi clase Foo sea capaz de crear barra de, sin conocer la aplicación exacta detrás IBar? me ocurre 4 soluciones aquí, pero todos ellos parecen tener inconvenientes:

  1. inyectables del tipo de objeto y que utilizan la reflexión
  2. utilizando los genéricos
  3. el uso de "Servicio de localización" y llamando a la Resolve () método.
  4. la creación de una clase de fábrica separados e inyectarlo en Foo:

class Foo 
{ 
    public void DoSmth(IBarCreator barCreator) 
    { 
     var newBar = barCreator.CreateBar(); 
    } 
} 

interface IBarCreator 
{ 
    IBar CreateBar(); 
} 

class BarCreator : IBarCreator 
{ 
    public IBar CreateBar() 
    { 
     return new Bar(); 
    } 
} 

último caso parece natural, pero la clase BarCreator tiene código demasiado Litle. Entonces, ¿cómo crees que es mejor?

+1

La opción 4 es la respuesta correcta: http://stackoverflow.com/questions/1943576/is-there-a-pattern-for-initializing-objects-created-via-a-di-container/1945023#1945023 –

+1

Sin embargo, ¿por qué quieres que Foo cree el IBar? Sé consciente de las abstracciones fugaces. –

Respuesta

0

Siento cuando dices "Quiero que mi clase Foo pueda crear Bar's" una regla más viene a jugar que es "Separación de preocupaciones". Por lo tanto, debe delegar la tarea de creación de clases en otra cosa y Foo no debe preocuparse por esa tarea.

2

todo depende de su escenario exacto y sus necesidades.
Creo que el enfoque más utilizado es, como ha mencionado, un factory.
Si está utilizando un marco IoC (como Ninject o Sprint.Net, Castle Windsor, etc. consulte here), un localizador de servicios también es una solución viable.

3

Me gusta "inyectar" un Func<IBar> en este caso. Como lo siguiente:

class Foo 
{ 
    public Foo(Func<IBar> barCreator) 
    { 
     this.bar = barCreator(); 
    } 

    private IBar bar; 
} 

interface IBar 
{ 
} 
2

Si tiene un problema con la interfaz de fábrica redundante, puede tomar dos enfoques aquí.

Que sea reutilizable con los genéricos:

interface IFactory<T> 
{ 
T Create(); 
} 

class DefaultConstructorFactory<T> : IFactory<T>, where T: new() 
{ 
public T Create() { return new T();} 
} 

o utilizar la función anónima como una fábrica:

public void DoSomething(Func<IBar> barCreator) 
{ 
var newBar = barCreator(); 
//... 
} 
+0

Esto no funciona, ¿verdad? No puede pasar un 'DefaultConstructorFactory ' como un 'IFactory ' – fearofawhackplanet

3

Esto es lo que se hicieron para fábricas.

Si cree que su fábrica tiene muy poco código, pregúntese qué beneficio le brinda al crear la instancia en línea. Si los beneficios superan los costos del código agregado, entonces no se preocupe.

Personalmente, evitaría la ubicación del servicio, o si realmente la debe usar, la escondería detrás de una fábrica de todos modos. La ubicación del servicio tiende a ser abusada fácilmente, y puede llevar a que su contenedor encuentre su camino en el código con el que no debería tener nada que ver.

Para mayor comodidad, algunos contenedores le permiten especificar una fábrica para ser utilizada por el contenedor cuando crea una instancia de un componente. En este caso, su clase podría depender de IBar directamente, pero su contenedor llamaría al IBarCreator cuando necesite una nueva instancia.Castle Windsor tiene los métodos UseFactory y UseFactoryMethod en su API, por ejemplo.

Cuestiones relacionadas