代码改变世界

Inversion of Control Containers and the Dependency Injection pattern 之读书笔记一

2012-06-27 14:50  Lance Ma  阅读(286)  评论(1编辑  收藏  举报

今天,读了马丁福勒的一篇文章题目是:Inversion of Control Containers and the Dependency Injection pattern。有了一些自己的理解,所以记在这里。

第一点: Components and Services

I use component to mean a glob of software that's intended to be used, without change, by an application that is out of the control of the writers of the component. By 'without change' I mean that the using application doesn't change the source code of the components, although they may alter the component's behavior by extending it in ways allowed by the component writers.

A service is similar to a component in that it's used by foreign applications. The main difference is that I expect a component to be used locally (think jar file, assembly, dll, or a source import). A service will be used remotely through some remote interface, either synchronous or asynchronous (eg web service, messaging system, RPC, or socket.)

我的理解:component是本地的,一般不会发生变化的(当然可以扩展)。service是远程的,通过web service,消息系统,RPC,socket来同步或异步的调用。


第二点: Naive Example

Figure 1

Figure 1: The dependencies using a simple creation in the lister class

Figure 1 shows the dependencies for this situation. The MovieLister class is dependent on both the MovieFinder interface and upon the implementation. We would prefer it if it were only dependent on the interface, but then how do we make an instance to work with?

In my book P of EAA, we described this situation as a Plugin. The implementation class for the finder isn't linked into the program at compile time, since I don't know what my friends are going to use. Instead we want my lister to work with any implementation, and for that implementation to be plugged in at some later point, out of my hands. The problem is how can I make that link so that my lister class is ignorant of the implementation class, but can still talk to an instance to do its work.

Expanding this into a real system, we might have dozens of such services and components. In each case we can abstract our use of these components by talking to them through an interface (and using an adapter if the component isn't designed with an interface in mind). But if we wish to deploy this system in different ways, we need to use plugins to handle the interaction with these services so we can use different implementations in different deployments.

So the core problem is how do we assemble these plugins into an application? This is one of the main problems that this new breed of lightweight containers face, and universally they all do it using Inversion of Control.

这里其实是解耦。具体地说,就是依赖反转(Dependency Inversion)。高层模块不应该依赖底层模块(相对于高层模块,底层是实现细节),而应该依赖抽象接口。底层模块依赖同样的抽象接口(主要是为了满足高层的调用需要,实现了那个抽象接口。也算是编译依赖吧)。

那么,高层模块如何在运行时选择哪个底层的实现呢?这就是Inversion of Control的用武之地了。

 

第三: Inversion of Control

When these containers talk about how they are so useful because they implement "Inversion of Control" I end up very puzzled. Inversion of control is a common characteristic of frameworks, so saying that these lightweight containers are special because they use inversion of control is like saying my car is special because it has wheels.

The question, is what aspect of control are they inverting? When I first ran into inversion of control, it was in the main control of a user interface. Early user interfaces were controlled by the application program. You would have a sequence of commands like "Enter name", "enter address"; your program would drive the prompts and pick up a response to each one. With graphical (or even screen based) UIs the UI framework would contain this main loop and your program instead provided event handlers for the various fields on the screen. The main control of the program was inverted, moved away from you to the framework.

Inversion of Control本是framework的一般特性,毫无特殊之处。这里马丁讲了他认为Inversion of Control的渊源。据我的理解就是好莱坞原则:don't call me,I will call you.

For this new breed of containers the inversion is about how they lookup a plugin implementation. In my naive example the lister looked up the finder implementation by directly instantiating it. This stops the finder from being a plugin. The approach that these containers use is to ensure that any user of a plugin follows some convention that allows a separate assembler module to inject the implementation into the lister.

As a result I think we need a more specific name for this pattern. Inversion of Control is too generic a term, and thus people find it confusing. As a result with a lot of discussion with various IoC advocates we settled on the name Dependency Injection.

I'm going to start by talking about the various forms of dependency injection, but I'll point out now that that's not the only way of removing the dependency from the application class to the plugin implementation. The other pattern you can use to do this is Service Locator, and I'll discuss that after I'm done with explaining Dependency Injection.

这里引出了Dependency Injection。为什么搞一个新名词呢?原来是那个老的名字太宽泛了,又挂羊头卖狗肉之嫌。所以,争论了半天,就发明了个新名字。这个名字更直白了:就是assembler把实现注入到高层模块对接口的引用处,所以就叫依赖注入。当然,依赖注入不是把应用和底层解耦的唯一方式,还有一个Service Locator。