如果已知具体类,为什么要使用IoC / DI?

时间:2013-03-21 21:45:48

标签: design-patterns dependency-injection inversion-of-control

我已经阅读了几天关于依赖注入/控制反转的内容,并且正在努力理解一个概念。

让我们假设我有以下琐碎的场景:

public interface ILocation
{
    string LocationName { get; set; }
}

// The implementation / concrete class for ILocation
public class Location : ILocation
{
    public string LocationName {
        get { /* logic */ }
        set { /* logic */ }
    }
}


// My class that depends on ILocation as a dependency
public class SomeClass{
    public SomeClass(ILocation location)
    {
        this.theLocation = location;
    }

    // 
    // more code...
    // 
}

很好,所以我将ILocation注入我的SomeClass ...但我必须在我的依赖注入框架中连接ILocation以由Location处理IN CODE并编译。 (旁白:我意识到有一些框架可以在文件中进行这种配置,即XML配置文件)

当编译时需要存在上面列出的所有组件时,创建知识“分离”的重点是什么?

这真让我烦恼。也许我完全错过了这一点。现在,话虽如此,我确实看到很多人谈论“可测试性”,我可以看到它的优势,但让我们假设我们正在抛出测试窗外;还有什么优点?这个真的给了我什么?

我最初想要了解这个概念,希望能找到一个为我正在构建的应用程序设计“插件”模式的好方法。到目前为止,这看起来似乎不适用于运行时插件的概念。

期待对这个主题的见解 - 谢谢!

4 个答案:

答案 0 :(得分:2)

依赖注入的第一个目标是使代码易于单元测试。

然后获得额外的优势,例如注入代理(AOP,用于事务,安全检查等)的可能性,配置注入的组件,根据配置文件或配置选择实现等。所有这些取决于你的框架的功能。

答案 1 :(得分:2)

让我们上课并摆脱DI。

public class SomeClass
{
    private Location _location = new Location();
    public SomeClass()
    {
    }
}

很好,您可以创建Location对象,并且它的构造函数中不包含任何参数。代码看起来很漂亮,这很容易吗?但是等等,现在对Location类进行了更改,需要它自己的依赖项LocationFinder。所以我们将它添加到对象构造中,也许我们将它移动到构造函数。

public class SomeClass
{
    private Location _location;
    public SomeClass()
    {
         _location = new Location(new LocationFinder());
    }
}

好的,不太漂亮但仍然不太糟糕。但确定6个月之后,LocationFinder必须改变,现在它需要从一个工厂,LocationFinderFactory创建,它有自己的依赖项。

public class SomeClass
{
    private Location _location;
    public SomeClass()
    {
        var locationFinderFactory = new LocationFinderFactory(new LocationFinderStrategy());
        _location = new Location(locationFinderFactory.Create());
    }
}

不太干净不对吗?更值得注意的是,每次Location实现发生变化时,您都必须更改SomeClass。 您已将SomeClass的实现与Location和其他3个类相结合!现在,每当这4个类中的任何一个必须更改时,您将更改SomeClass。

故事的道德,以松散耦合的方式编写您的类(例如使用DI),这些类型的代码更改将仅本地化为它应该影响的类。

答案 2 :(得分:1)

您获得的是分离关注点。使用DI,您可以自由更改实现或交换ILogger 的实现,而无需修改(甚至重新编译)SomeClass。使用DI,SomeClass并不关心实现ILogger接口的类,只要它实现接口中的所有方法即可。如果您使用了具体的类,如果您想要更改实现方法的类,则还必须修改SomeClass。使用DI,您需要更改的是发送给构造函数的类或IoC容器的配置,而无需修改SomeClass本身。

答案 3 :(得分:0)

管理系统内部依赖关系的方式会对软件质量产生巨大影响(灵活性,健壮性,可重用性和可维护性),尤其是从长远来看,随着时间的推移,系统会经历很多变化。 依赖注入是管理依赖关系的一个强大工具(等等)。

本文精美地讨论了这个主题,因此我不会尝试复制它:) http://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf