为什么要使用IoC框架

时间:2010-09-28 18:44:59

标签: ioc-container ninject

我一直在阅读关于控制框架的反转,我只是在讨论这个问题:“为什么我到底需要一个框架才能做到这一点?”

不要误解我的问题......这种模式是我们程序员经常使用的,但是......一个功能齐全的框架可以做到这一点?

我必须遗漏一些东西,这就是我发布问题的原因。我在网上看到了很多例子,我只是不明白。 mi可能会被这个想法所阻挡。

只需看一下Ninject主页的例子:

public class Samurai {
    public IWeapon Weapon { get; private set; }
    public Samurai(IWeapon weapon) {
        Weapon = weapon;
    }
}

public class WarriorModule : NinjectModule {
    public override void Load() {
        Bind< IWeapon >.To< Sword >();
    }
}

“Samurai”课对我来说没问题。我不需要“NinjectModule”框架。

我假设稍后会在代码中创建新的“Samurai”实例,并将“Sword”实例传递给它,例如:

Samurai theWarrior = new Samurai(WarriorModule.GetInstance(IWeapon));//no coupling

可以替换为:

Samurai theWarrior = new Samurai(new Sword());//still no coupling

Samurai theWarrior = new Samurai(GetWeaponFromXML());//no coupling yet

我错过了什么部分?您能否介绍一下我的应用程序中可能需要Ioc框架的场景?

感谢。

4回答之后的更新:我真的很喜欢我们从你们那里得到的所有答案。我刚刚阅读了这篇文章dependency-injection-dissection/,其中那个人用它来进行单元测试和你刚才提供的StackOverflow链接。是的,我错过了那个重大的复杂部分,所以让我自己定制使用IoC框架。再次感谢。

我会投票给你答案,但我只是得到一条橙色信息,说我不能。

感谢那位突出显示我发布的代码的人。

4 个答案:

答案 0 :(得分:6)

这是代码示例的问题。它们要么复杂而你没有解释你的观点,要么它们是微不足道的,然后看起来毫无意义。

WarriorModule正在做的是将具体类型绑定到接口,因此每当另一个类需要该接口的实现时,它就会由IoC容器自动接收。具有依赖性的类不依赖于具体类型,因此具有较低的耦合和较高的可测试性。我想你已经知道了。

在你的替换场景中,Samurai类没有耦合到剑类,但调用代码仍然是。您可以将其推出另一个级别,但该代码现在具有依赖性,您的干预类现在必须编组所有依赖项。

IoC容器为所有映射执行此操作,仅将其放在几个位置(模块类)。其余的代码是免费的,不关心,不依赖于具体的类型。

希望有所帮助。

答案 1 :(得分:4)

你的例子很简单,只有两层,但是当你有一个真实的例子时很快就会变得混乱:

var form = new OrderEntryForm(
    new OrderService(
        new OrderReposity(
            new DatabaseGateway(
                new DataProviderFactory()))))

IoC容器可以为您完成所有连接,让您的生活更轻松。

这是一个类似问题的例子,其中包含所有细节: https://stackoverflow.com/questions/45191/ioc-explain-and-more-important-when-to-use-it/45197#45197

答案 2 :(得分:1)

我最近开始使用Unity for IoC,毫无疑问它让我的生活更轻松。

我会逐字地粘贴我的代码并希望您发现它很有用。更有经验的人可能会给你更多。

另外,我发现阅读Fowler关于DI的论文很有用。

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        using (IUnityContainer container = new UnityContainer())
        {
            container

                .RegisterType<ILogger, StatSyncherFormView>(new myLife())

                // GUI
                .RegisterType<IStatSyncherView, StatSyncherFormView>()

                // Services
                .RegisterType<ISalesForceWebServices, SalesForceWebServices1>()

                .RegisterInstance(new SalesForceWebServices1(
                    "XXX", "XXX",
                   "https://login.salesforce.com/services/Soap/c/19.0/0DF70000000CfHq",
                    "https://na5-api.salesforce.com/services/Soap/s/19.0"))


                .RegisterType<ISalesForceService, SalesForceService1>()

                .RegisterType<IRestApiCall, RestApiCall1>()

                .RegisterType<IDirectTrackService, DirectTrackService1>()

                .RegisterType<IDAgentsService, DAgentsService1>()

                .RegisterType<IQuickBooksService, QuickBooksService1>();

            StatSyncherPresenter p = container.Resolve<StatSyncherPresenter>();

            Application.Run((Form)p.view);
        }
    }

我觉得最有用的一件事是:

public class AnyClassCreatedByContainer
{
    [Dependency]
    public ILogger Logger { get; set; }
}

答案 3 :(得分:1)

虽然Samurai theWarrior = new Samurai(new Sword());仍然没有耦合,但是如果你想要在你的应用程序中给所有武士<insert favourite weapon here>,你必须改变你所有的调用代码以换成新武器,而使用IoC你会在一个地方改变它,你所有的武士都会使用新武器。