什么是IOC?需要一些实用的代码示例来说明

时间:2009-02-26 19:47:15

标签: inversion-of-control

有人可以指导我参加IOC的一些基础教程吗? (最好是.net / c#)。

我需要一些代码来帮助我解决它:)

IOC与DDD类似吗?或测试驱动设计?

7 个答案:

答案 0 :(得分:12)

在大多数应用程序中,IOC或控制反转是通过代码从UI转换到数据库的路径。这不是一个完整的答案,但它是了解这个概念的最简单方法之一。

如果您想学习IOC,请进入TDD,因为您会发现一旦反转,设置测试就会轻松得多。

示例:

我见过的大多数.NET应用程序的典型流程都是这样的:

UserCollection col = BusinessLayer.Class.GetLoggedInUsers();
//Business logic
return col;

那么生意是这样的:

UserTable table = DataLayer.Class.GetLoggedInUsers();
return table;

等。这都是伪代码。要在此示例中使用IOC,请为数据层类添加接口,如IUserRepository。你可以使用泛型,我会推荐在引擎盖下。

然后你可以这样做:

IUserRepository repository = SetUpRepository();
UserCollection col = BusinessLayer.Class.GetUsers(repository);

为什么这很重要?对于测试,您可以创建模拟存储库并将其提供给业务类。模拟包含始终相同的数据,这意味着您正在练习代码,而不是端到端测试。

如果您想要C#,这是weblogs.asp.net上的基本示例:

答案 1 :(得分:9)

从Martin Fowler那里读到这篇优秀的article

另外,请查看wikipedia article

依赖注入是控制反转的最着名的例子,简而言之就是你的代码:

public class FileReader { }
public class Application {
    // inflexible concrete dependency
    private FileReader fileReader = new FileReader(); 
}

要:

public interface Reader {}
public class FileReader implements Reader {}
public class Application {
    // flexible abstract dependency injected in
    private Reader reader;

    public Application(Reader reader) { // constructor injection
        this.reader = reader;
    }
    public void setReader(Reader reader) { // setter injection
        this.reader = reader;
    }
}

答案 2 :(得分:7)

谈谈行话,控制反转是一种支持(其中包括)单一责任原则的模式。

为了解释为什么所有这些都有用,你需要一些说明,所以请耐心等待。

单一责任基本上意味着您的班级应尽可能独立于系统的其他部分,以尽量减少更改一个部分对另一部分的影响。 (您还可以将此更改为更改实现不应该触发重新编译项目中的所有文件的事实,例如在C / C ++项目中更改.h文件时的情况)。 副作用是你最终得到了许多只做一件事的小物件,但很好(在理想的世界里)

但在大多数情况下,为了完成其工作,一个对象需要与其他对象交谈:它取决于它们。

缓解的第一部分是将实现与接口分开。这意味着依赖于接口(或纯粹的抽象类,取决于您选择的语言),以便一个对象不依赖于另一个对象的具体实现。

因此,要使用规范示例,在业务层需求中,您需要执行需要访问的功能 - 用于检索对象的数据层 - 其他一些服务 - 记录信息和/或错误的记录器

反过来,每个服务或依赖项都有自己的依赖项,即使它不使用它们,您的类也需要注意这些依赖项。 根据引用的数量,设置对象可能会快速失控。现在将它乘以你需要编写的类的数量,最后得到一堆东西。

使用IOC容器基本上可以帮助您摆脱这种混乱。 当你需要一个物体时,你不会“新起来”。相反,您要求IOC容器为您检索它。 容器负责提供准备使用的功能对象,无论其依赖性如何。

这意味着你的类不需要知道它所依赖的类的依赖性,这会减少纠结。 此外,它不需要知道实际的类实现它依赖的服务,这意味着 - 服务实现可以在另一个项目(dll或其他)中定义,因此修改它永远不会影响你的类 - 实现可以是不同的实现,具体取决于上下文(考虑更改数据库,甚至根据配置甚至应用程序的当前状态转到Web服务来检索信息)。

为了尝试回答您的其他问题,IOC是一种模式。 TDD和DDD是设计方法,因此不能将另一方面等同。 但IOC是支持TDD或DDD的宝贵工具。

我知道首字母缩略词汤和你可以找到的部分样本并不容易。我能给你的最好的建议就是尝试一些小项目,你将抛弃的原型,只是为了处理这些事情。如果你正在寻找工作,这不是一个简单的方法,但绝对值得,只是从个人的角度来看。

希望有所帮助。

答案 3 :(得分:4)

不,IoC不是DDD或TDD。

Martin Fowler的article是一个很好的介绍。

答案 4 :(得分:1)

关于IOS的问题,维基百科有一个fairly extensive explanation

关于教程或示例this,教程非常清楚并且有很多示例代码。

答案 5 :(得分:0)

如果您了解DIP(依赖倒置原则),IOC就是蛋糕。我建议在学习模式之前学习面向对象的原则。核心原则可以像legos一样堆叠以完成任何模式。 Brandon Joyce

答案 6 :(得分:0)

控制反转是逻辑结构的抽象。一种方法(通常与IoC同义)是依赖注入,它抽象对象之间的引用。当对象从应用程序的实现细节中解放出来时,例如哪个类实现了哪些服务,他们可以自由地专注于他们的核心功能。

例如,假设您有一个需要将Foo个对象映射到Bar个对象的类。你可以这样写:

public class FooMapper
{
    public Bar Map(Foo foo)
    {
        // ...
    }
}

并像这样使用它:

public class NeedsToMapFoos
{
    public void MapSomeFoos()
    {
        var fooMapper = new FooMapper();

        // ...
    }
}

虽然有效,但这也很严格。 NeedsToMapFoos只关心映射发生,而不是以任何特定方式发生。

我们可以用界面表示“操作无实现”的概念:

public interface IFooMapper
{
    Bar Map(Foo foo);
}

并声明对该操作的依赖:

public class NeedsToMapFoos
{
    private readonly IFooMapper _fooMapper;

    public NeedsToMapFoos(IFooMapper fooMapper)
    {
        _fooMapper = fooMapper;
    }

    public void MapSomeFoos()
    {
        // ...use _fooMapper...
    }
}

现在NeedsToMapFoos知识较少,这意味着它不那么复杂。可以自由地专注于商业案例,而不是履行行政职责。

像这样的精心设计的对象也更具适应性。正如钻石是刚性的,粘土是可塑的,内部结构决定了对变化的反应。

最后,用这种风格编写的逻辑也很灵活。假设FooMapper.Map是一项昂贵的操作,应该进行缓存。您可以使用装饰器模式来包装现有实现,并将其无缝地传递给NeedsToMapFoos

public class CachingFooMapper : IFooMapper
{
    private readonly IFooMapper _innerMapper;
    private readonly IDictionary<Foo, Bar> _cache;

    public CachingFooMapper(IFooMapper innerMapper)
    {
        _innerMapper = innerMapper;
    }

    public Bar Map(Foo foo)
    {
        // Read bar from _cache. If not there, read from inner mapper and add to _cache.
    }
}

// Usage

new NeedsToMapFoos(new CachingFooMapper(new FooMapper()));