php为何要用依赖注入?
由于依靠注入会落低依靠和被依靠类型间的耦合,在修改被依靠的类型实现时,不需要修改依靠类型的实现;同时,关于依靠类型的测试,可以更利便的使用“mocking object”替换原有的被依靠类型,以到达对依靠对象独立停止单元测试的目的。
0. 前言
在软件工程领域,依靠注入(Dependency Injection)是用于实现操纵反转(Inversion of Control)的最常见的方式之一。本文主要介绍依靠注入道理和常见的实现方式,重点在于介绍这种年轻的设计模式的适用处景及优势。
1. 为什么需要依靠注入
操纵反转用于解耦,解的毕竟是谁和谁的耦?这是我在最初理解依靠注入时候发生的第一个问题。
下面我援用Martin Flower在说明介绍注入时使用的一部分代码来说明这个问题。
public class MovieLister { private MovieFinder finder; public MovieLister() { finder = new MovieFinderImpl(); } public Movie[] moviesDirectedBy(String arg) { List allMovies = finder.findAll(); for (Iterator it = allMovies.iterator(); it.hasNext();) { Movie movie = (Movie) it.next(); if (!movie.getDirector().equals(arg)) it.remove(); } return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]); } ... }
public interface MovieFinder { List findAll(); }
我们创立了一个名为MovieLister的类来供给需要的电影列表,它moviesDirectedBy办法供给按照导演名来搜索电影的方式。真正负责搜索电影的是实现了MovieFinder接口的MovieFinderImpl,我们的MovieLister类在结构函数中创立了一个MovieFinderImpl的对象。
当前看来,一切都不错。但是,当我们但愿修改finder,将finder更换为一种新的实现时(比方为MovieFinder增添一个参数表白Movie数据的来源是哪个数据库),我们不仅需要修改MovieFinderImpl类,还需要修改我们MovieLister中创立MovieFinderImpl的代码。
这就是依靠注入要处置的耦合。这种在MovieLister中创立MovieFinderImpl的方式,使得MovieLister不仅仅依靠于MovieFinder这个接口,它还依靠于MovieListImpl这个实现。 这种在一个类中直接创立另一个类的对象的代码,和硬编码(hard-coded strings)乃至硬编码的数字(magic numbers)一样,是一种致使耦合的坏味道,我们可以把这种坏味道称为硬初始化(hard init)。同时,我们也应当像记住硬编码一样记住,new(对象创立)是有毒的。
Hard Init带来的主要害处有两个方面:1)上文所述的修改其实现时,需要修改创立处的代码;2)不便于测试,这种方式创立的类(上文中的MovieLister)没法独自被测试,其行动和MovieFinderImpl紧紧耦合在一起,同时,也会致使代码的可读性问题(“假如一段代码不便于测试,那么它必然不便于阅读。”)。
2. 依靠注入的实现方式
依靠注入其实并不奇妙,我们日常的代码中许多都用到了依靠注入,但很少留意到它,也很少主动使用依靠注入停止解耦。这里我们简便介绍一下赖注入实现三种的方式。
2.1 结构函数注入(Contructor Injection)
这是我认为的最简便的依靠注入方式,我们修改一下上面代码中MovieList的结构函数,使得MovieFinderImpl的实此刻MovieLister类之外创立。这样,MovieLister就只依靠于我们定义的MovieFinder接口,而不依靠于MovieFinder的实现了。
public class MovieLister { private MovieFinder finder; public MovieLister(MovieFinder finder) { this.finder = finder; } ... }
2.2 setter注入
相似的,我们可以增添一个setter函数来传入创立好的MovieFinder对象,这样一样可以幸免在MovieFinder中hard init这个对象。
public class MovieLister { s... public void setFinder(MovieFinder finder) { this.finder = finder; } }
2.3 接口注入
接口注入使用接口来供给setter办法,其实现方式如下。
第一要创立一个注入使用的接口。
public interface InjectFinder { void injectFinder(MovieFinder finder); }
之后,我们让MovieLister实现这个接口。
class MovieLister implements InjectFinder { ... public void injectFinder(MovieFinder finder) { this.finder = finder; } ... }
最后,我们需要按照不一样的框架创立被依靠的MovieFinder的实现。
3. 最后
依靠注入落低了依靠和被依靠类型间的耦合,在修改被依靠的类型实现时,不需要修改依靠类型的实现,同时,关于依靠类型的测试,可以更利便的使用mocking object替换原有的被依靠类型,以到达对依靠对象独立停止单元测试的目的。
最后需要留意的是,依靠注入只是操纵反转的一种实现方式。操纵反转还有一种常见的实现方式称为依靠查寻。
以上就是php为什么要用依靠注入?的具体内容,更多请关注百分百源码网其它相关文章!