代码改变世界

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

2012-06-29 15:35  Lance Ma  阅读(147)  评论(0编辑  收藏  举报

Forms of Dependency Injection

There are three main styles of dependency injection. The names I'm using for them are Constructor Injection, Setter Injection, and Interface Injection.

三种依赖注入:Constructor Injection, Setter Injection, and Interface Injection.

其实,这三种都是大同小异。何出此言?其实都是“接口”注入。这里接口加了引号,是为了区分Java中的interface。constructor也好,setter也罢,interface也罢,都是暴露的调用接口,在这点上是相同的。constructor和setter是暗规则(不强制提供,所以可能会有运行时错误),interface是明规则(强制实现,运行时有保证),区别仅此而已。Spring支持constructor和setter。

 

Using a Service Locator

The basic idea behind a service locator is to have an object that knows how to get hold of all of the services that an application might need. So a service locator for this application would have a method that returns a movie finder when one is needed. Of course this just shifts the burden a tad, we still have to get the locator into the lister, resulting in the dependencies of Figure 3

Figure 3

Figure 3: The dependencies for a Service Locator

 

我觉得,service locator可能算是一个应付简单情况的解决方案。

Using a Segregated Interface for the Locator

这一节只是告诉我,当你想解耦时,那就依赖抽象吧。

A Dynamic Service Locator

这一节真的没什么亮点,这种方案很鸡肋。正如马丁所说不够清晰,还不如简单的Service Locator的直接调用方法呢。

 

Deciding which option to use

抉择。

Service Locator vs Dependency Injection

The important difference between the two patterns is about how that implementation is provided to the application class. With service locator the application class asks for it explicitly by a message to the locator. With injection there is no explicit request, the service appears in the application class - hence the inversion of control.

Service Locator是直接调用,Dependency Injection是Inversion of Control。

Inversion of control is a common feature of frameworks, but it's something that comes at a price. It tends to be hard to understand and leads to problems when you are trying to debug. So on the whole I prefer to avoid it unless I need it. This isn't to say it's a bad thing, just that I think it needs to justify itself over the more straightforward alternative.

控制反转也是框架的常见特性,它也是有代价的:不好理解,不好调试。马丁的建议是:除非必要,否则不要用。换言之,用它需要有足够的理由,不能脑子一热就想用。

Constructor versus Setter Injection

Interface injection is more invasive since you have to write a lot of interfaces to get things all sorted out.

接口注入不推荐:有侵入性,而且还要提供好多接口,麻烦啊。

My long running default with objects is as much as possible, to create valid objects at construction time. This advice goes back to Kent Beck's Smalltalk Best Practice Patterns: Constructor Method and Constructor Parameter Method. Constructors with parameters give you a clear statement of what it means to create a valid object in an obvious place. If there's more than one way to do it, create multiple constructors that show the different combinations.

Another advantage with constructor initialization is that it allows you to clearly hide any fields that are immutable by simply not providing a setter. I think this is important - if something shouldn't change then the lack of a setter communicates this very well. If you use setters for initialization, then this can become a pain. (Indeed in these situations I prefer to avoid the usual setting convention, I'd prefer a method like initFoo, to stress that it's something you should only do at birth.)

那么,constructor和setter选哪个?优先选constructor injection。为何?constructor更清晰,明确地告诉你这样就可以构造一个对象,而且可以隐藏可读的属性。

凡事有个例外。

But with any situation there are exceptions. If you have a lot of constructor parameters things can look messy, particularly in languages without keyword parameters. It's true that a long constructor is often a sign of an over-busy object that should be split, but there are cases when that's what you need.

直接上结论了,中间太罗嗦了。

The current rush of lightweight containers all have a common underlying pattern to how they do service assembly - the dependency injector pattern. Dependency Injection is a useful alternative to Service Locator. When building application classes the two are roughly equivalent, but I think Service Locator has a slight edge due to its more straightforward behavior. However if you are building classes to be used in multiple applications then Dependency Injection is a better choice.

If you use Dependency Injection there are a number of styles to choose between. I would suggest you follow constructor injection unless you run into one of the specific problems with that approach, in which case switch to setter injection. If you are choosing to build or obtain a container, look for one that supports both constructor and setter injection.

The choice between Service Locator and Dependency Injection is less important than the principle of separating service configuration from the use of services within an application.