una que programacion interfaz interfaces implementacion declaracion c# .net dependency-injection inversion-of-control autofac

c# - que - MĂșltiples implementaciones para una interfaz con DI



implementacion de interfaces c# (1)

Su inversión del contenedor de control no es una fábrica per se. Su estuche es perfecto para el patrón de fábrica.

Crea una nueva fábrica abstracta que se utiliza para crear tus monstruos:

public interface IMonsterFactory { Zombie CreateZombie(string name); Vampire CreateVampire(int age); }

Y luego registrar su implementación en Autofac.

Finalmente usa la fábrica en tu clase:

class Graveyard : ILocation { IMonsterFactory _monsterFactory; public Graveyard(IMonsterFactory factory) { _monsterFactory = factory; } public void PresentLocalCreeps() { var vampire = _monsterFactory.CreateVampire(300); vampire.IntroduceYourself(); var zombie = _monsterFactory.CreateZombie("Rob"); zombie.IntroduceYourself(); } }

Por supuesto, también puedes usar fábricas de monstruos específicas si lo deseas. No obstante, el uso de interfaces hará que su código sea mucho más legible.

Actualizar

¿Pero cómo implementaría la fábrica? Por un lado, la fábrica no debe usar el contenedor IOC para crear los monstruos, porque eso se considera malo (degrada el patrón DI al anti-patrón del localizador de servicios).

Me estoy cansando tanto de escuchar que SL es un anti-patrón. No es. Como con todos los patrones, si lo usas incorrectamente, te dará una desventaja. Eso aplica para TODOS los patrones. http://blog.gauffin.org/2012/09/service-locator-is-not-an-anti-pattern/

Pero en este caso, no veo por qué no puede crear las implementaciones directamente en su fábrica. Para eso es la fábrica:

public class PreferZombiesMonsterFactory : IMonsterFactory { public Zombie CreateZombie(string name) { return new SuperAwesomeZombie(name); } public Vampire CreateVampire(int age) { return new BooringVampire(age); } }

No es más complicado que eso.

Por otro lado, la fábrica no debe crear los monstruos, ya que esto evitaría el contenedor de COI y acoplaría firmemente a la fábrica y los monstruos. ¿O estoy de nuevo en el camino equivocado? ;-)

No importa que la fábrica esté bien acoplada a las implementaciones de monstruos. Porque ese es el propósito de la fábrica: abstraer la creación del objeto, para que nada más en su código sea consciente de los concretos.

Podría crear SuperDeluxeMonsterFactory , MonstersForCheapNonPayingUsersFactory , etc. El resto del código de su aplicación no sería consciente de que está usando diferentes monstruos (utilizando diferentes fábricas).

Cada vez que tiene que cambiar los concretos, puede cambiar de fábrica o simplemente modificar la fábrica existente. Ningún otro código se verá afectado siempre y cuando sus implementaciones de monstruos no violen el Principio de Sustitución de Liskov.

Contenedor de fábrica vs IoC

Entonces, ¿cuál es la diferencia entre una fábrica y un contenedor de IoC? El IoC es excelente para resolver dependencias para sus clases y mantener el tiempo de vida (el contenedor puede, por ejemplo, eliminar todos los elementos desechables automáticamente cuando finaliza una solicitud HTTP).

La fábrica, por otro lado, sobresale en crear objetos para ti. Hace eso y nada más.

Resumen

Entonces, si en algún lugar de su código necesita obtener un tipo específico de implementación, normalmente debería usar una fábrica. La propia fábrica PUEDE utilizar el IoC como un localizador de servicios internamente (para resolver dependencias). Eso está bien ya que es un detalle de implementación en la fábrica que no afecta nada más en su aplicación.

Use el contenedor IoC (mediante inyección de dependencia) si desea resolver un servicio (y no le importa qué implementación obtiene, o si obtiene una instancia creada anteriormente).

Ahora mismo estoy tratando de enseñarme el patrón de inyección de dependencia con el contenedor IOC de Autofac. He venido con un ejemplo muy simple, que se presenta a continuación. Aunque el ejemplo es simple, no logro que funcione correctamente.

Aquí están mis clases / interfaces:

Dos monstruos, ambos implementando la interfaz IMonster:

interface IMonster { void IntroduceYourself(); } class Vampire : IMonster { public delegate Vampire Factory(int age); int mAge; public Vampire(int age) { mAge = age; } public void IntroduceYourself() { Console.WriteLine("Hi, I''m a " + mAge + " years old vampire!"); } } class Zombie : IMonster { public delegate Zombie Factory(string name); string mName; public Zombie(string name) { mName = name; } public void IntroduceYourself() { Console.WriteLine("Hi, I''m " + mName + " the zombie!"); } }

Luego está mi cementerio:

interface ILocation { void PresentLocalCreeps(); } class Graveyard : ILocation { Func<int, IMonster> mVampireFactory; Func<string, IMonster> mZombieFactory; public Graveyard(Func<int, IMonster> vampireFactory, Func<string, IMonster> zombieFactory) { mVampireFactory = vampireFactory; mZombieFactory = zombieFactory; } public void PresentLocalCreeps() { var vampire = mVampireFactory.Invoke(300); vampire.IntroduceYourself(); var zombie = mZombieFactory.Invoke("Rob"); zombie.IntroduceYourself(); } }

Y finalmente mi principal:

static void Main(string[] args) { // Setup Autofac var builder = new ContainerBuilder(); builder.RegisterType<Graveyard>().As<ILocation>(); builder.RegisterType<Vampire>().As<IMonster>(); builder.RegisterType<Zombie>().As<IMonster>(); var container = builder.Build(); // It''s midnight! var location = container.Resolve<ILocation>(); location.PresentLocalCreeps(); // Waiting for dawn to break... Console.ReadLine(); container.Dispose(); }

Y este es mi problema: durante el tiempo de ejecución, Autofac lanza una excepción en esta línea:

var vampire = mVampireFactory.Invoke(300);

Parece que el mVampireFactory está tratando de crear una instancia de un zombie. Por supuesto, esto no funcionará ya que el constructor del zombie no tomará un int.

¿Hay una manera simple de arreglar esto? ¿O me di cuenta de que Autofac funciona completamente mal? Como resolverías este problema?