多个实现一个接口用DI [英] Multiple implementations for one interface with DI

查看:206
本文介绍了多个实现一个接口用DI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

现在,我想教自己与IOC容器从Autofac IoC的模式。我想出了一个很简单的例子,这是低于psented $ P $。虽然例子很简单,我没有得到它正常工作。

Right now I'm trying to teach myself the Dependency Injection pattern with the IOC-container from Autofac. I've come up with a very simple example, which is presented below. Although the example is simple, I fail to get it working properly.

下面是我的类/接口:

两个怪物,既实现IMonster接口:

Two monsters, both implementing the IMonster interface:

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!");
  }
}

再有就是我的墓地:

Then there's my graveyard:

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();
  }
}

最后我主要的:

And finally my main:

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();
}

这是我的问题: 在运行时,Autofac在这条线将引发异常:

And this is my problem: During runtime, Autofac throws an exception on this line:

var vampire = mVampireFactory.Invoke(300);

看来,mVampireFactory实际上是试图实例化一个僵尸。当然,这是行不通的,因为僵尸的构造不会采取一个int。

It seems that the mVampireFactory is actually trying to instantiate a zombie. Of course this won't work since the zombie's constructor won't take an int.

有没有解决这个问题的简单方法? 还是我得到的方式Autofac工作完全错了吗? 你将如何解决这个问题?

Is there a simple way to fix this? Or did I get the way Autofac works completely wrong? How would you solve this problem?

推荐答案

您控制容器的倒置不是工厂本身。你的情况是非常适合工厂模式。

Your inversion of control container is not a factory per se. Your case is a perfect fit for the factory pattern.

创建一个新的抽象工厂,用于创建您的怪物:

Create a new abstract factory which is used to create your monsters:

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

,然后注册其Autofac实施。

And then register its implementation in Autofac.

最后使用的工厂类:

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();
  }
}

您当然可以使用特定的怪物工厂太多,如果你想要的。尽管如此,使用接口将恕我直言,让你的codeA很多更具可读性。

You can of course use specific monster factories too if you want. None the less, using interfaces will imho make your code a lot more readable.

不过,我将如何实现工厂?一方面,厂家不应该使用IOC容器创造的怪物,因为这是被认为邪恶(降低了DI模式的服务定位器反模式)。

But how would I implement the factory? On the one hand the factory should not use the IOC container to create the monsters, because that's considered evil (degrades the DI pattern to the service locator anti-pattern).

我得到这么累听说SL是一个反模式。不是。如同所有的模式,如果不正确地使用它,它会给你一个缺点。这适用于所有的模式。 <一href="http://blog.gauffin.org/2012/09/service-locator-is-not-an-anti-pattern/">http://blog.gauffin.org/2012/09/service-locator-is-not-an-anti-pattern/

I'm getting so tired of hearing that SL is an anti-pattern. It's not. As with all patterns, if you use it incorrectly it will give you a disadvantage. That applies for ALL patterns. http://blog.gauffin.org/2012/09/service-locator-is-not-an-anti-pattern/

但在这种情况下,我不明白为什么你不能直接在您​​的工厂创造的实现?这就是工厂是:

But in this case I don't see why you can't create the implementations directly in your factory? That's what the factory is for:

public class PreferZombiesMonsterFactory : IMonsterFactory
{
    public Zombie CreateZombie(string name)
    {
        return new SuperAwesomeZombie(name);
    }

    public Vampire CreateVampire(int age)
    {
        return new BooringVampire(age);
    }
}

这不是要复杂得多。

It's not more complicated than that.

在另一方面,工厂不应造成怪物本身,因为这将绕过IOC容器,并紧密结合工厂和怪物。还是我在错误的轨道了吗? ;-)

On the other hand the factory should not create the monsters itself, because that would bypass the IOC-container and tightly couple the factory and the monsters. Or am I on the wrong track again? ;-)

有不要紧,工厂tighly耦合到怪物实现。因为这是工厂的宗旨:抽象出来的​​对象创建,因此没有别的在code是意识到了混凝土的

It doesn't matter that the factory is tighly coupled to the monster implementations. Because that's the purpose of the factory: To abstract away the object creation, so that nothing else in your code is aware of the concretes.

您可以创建 SuperDeluxeMonsterFactory MonstersForCheapNonPayingUsersFactory 等所有其他code。在您的应用程序不会知道您正在使用不同的怪物(通过使用不同的工厂)。

You could create SuperDeluxeMonsterFactory, MonstersForCheapNonPayingUsersFactory etc. All other code in your application wouldn't be aware of that you are using different monsters (by using different factories).

每个时间你必须改变混凝土你要么开关厂,或者你只是修改现有的工厂。没有其他的code会受到影响,只要你的怪物实现不违反Liskovs替换原则。

Each time you have to change concretes you either switch factory or you just modify the existing factory. No other code will be affected as long as your monster implementations do not violate Liskovs Substitution Principle.

那么,什么是一个工厂,一个IoC容器,然后有什么区别?国际奥委会伟大的解决依赖于你的类和维持寿命(容器例如可以自动处理所有一次性HTTP请求结束时)。

So what's the difference between a factory and a IoC container then? The IoC is great at resolving dependencies for your classes and maintain the lifetimes (the container can for instance dispose all disposables automatically when a HTTP request ends)..

在另一方面,工厂擅长于为你创建对象。它确实是,没有别的。

The factory on the other hand excels at creating objects for you. It does that and nothing else.

摘要

所以,如果你放在你的code需要得到你通常应该使用一个工厂的实现的特定类型。工厂本身可以使用国际奥委会作为一个服务定位器内部(解决依赖性)。这是确定的,因为它是一个实现细节在不影响应用程序中的任何其他工厂。

So if you somewhere in your code need to get a specific type of an implementation you typically should use a factory. The factory itself CAN use the IoC as a service locator internally (to resolve dependencies). That is OK since it's a implementation detail in the factory which do not affect anything else in your application.

使用IoC容器(通过依赖注入),如果要解决服务(并不在乎它的实现你得到的,或者如果你获得了previously创建的实例)。

Use the IoC container (through dependency injection) if you want to resolve a service (and do not care which implementation you get, or if you get a previously created instance).

这篇关于多个实现一个接口用DI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆