di 依赖注入实现的意义是什么?

2016-08-17 20:33:36 +08:00
 lml12377

一般的 PHP 框架,一个应用 Application ,生命周期大概是这样的: Request > Router / Url > Dispatch > Controller/Action [ > Service] > Model > [ > View] > Response ,当然可能有些差别,多数无外乎这样。

那引入 di 注入的意义是什么呢?是为了把应用流程涉及的对象设计成组件来实现解耦吗?比如 RequestInterface / HttpRequest / CliRequest , RouterInterface / SimpleRouter / RegexRouter / MapRouter 等等这样?

但是一个普通的带视图带数据库操作的请求大致流程大家都一样啊( ROR / J2EE / PHP MVC ),即使是 restful 也是有 Router / Request / ControllerAction / Response 的,这解耦的意义是什么呢?解来解去,还得捞出来组个 MVC 流程。

就好像 Router 妥妥的依赖 Request ,那就手工注入喽? Router 构造函数参数是 RequestInterface $request 喽?当前应用入口决定注入何种 Request 对象喽?难不成哪天 Router 还依赖个奇怪的玩意不成?

难道说仅仅是为了 mock 方便?还是说为了不确定的将来?还是说有其它的原因。。。

3808 次点击
所在节点    程序员
13 条回复
sunsh217
2016-08-17 20:46:39 +08:00
没有意义 ,装逼货。
sunsh217
2016-08-17 20:47:52 +08:00
把简单事情搞复杂,是装逼的必要条件 。 DI 依赖,就是这么个装逼货。
kungfuchicken
2016-08-17 21:00:08 +08:00
依赖注入和 MVC 没有直接关系,设计这个东西主体思想是解耦,服务化接口。

比如说很多服务,数据库,缓存,日志,相关的业务模块服务化之后,你替换掉其中任意一个具体的实现类,是不影响依赖这个服务的对应的业务和逻辑

引自维基百科:
Class A 中用到了 Class B 的对象 b ,一般情况下,需要在 A 的代码中显式的 new 一个 B 的对象。

采用依赖注入技术之后, A 的代码只需要定义一个私有的 B 对象,不需要直接 new 来获得这个对象,而是通过相关的容器控制程序来将 B 对象在外部 new 出来并注入到 A 类里的引用中。而具体获取的方法、对象被获取时的状态由配置文件(如 XML )来指定。

```
class Human {
...
protected $father;
...
public _construct() {
$this->father = new Father();
}
}
```
仔细看这段代码我们会发现存在一些问题:
(1). 如果现在要改变 father 生成方式,如需要用 new Father('name')初始化 father ,需要修改 Human 代码;
(2). 如果想测试不同 Father 对象对 Human 的影响很困难,因为 father 的初始化被写死在了 Human 的构造函数中;
(3). 如果 new Father()过程非常缓慢,单测时我们希望用已经初始化好的 father 对象 Mock 掉这个过程也很困难。
levn
2016-08-17 21:43:26 +08:00
在一个地方维护对象之间在构建时的依赖关系
neoblackcap
2016-08-17 21:48:29 +08:00
依赖注入是控制反转的一种实现方式,高层次的逻辑不用了解底层的实现方式,而且可以跟依赖解耦。
而且依赖注入解决了一些比如循环引用的问题。
至于你发现它不好用那是你的业务逻辑没达到它适用的程度,这个时候一般有两种做法,你适应它,或者抛弃它。
当然依赖注入最好用的地方就是测试,因为你可以轻易 mock 掉依赖的对象。
miao1007
2016-08-17 22:14:59 +08:00
多人编程时,实现解耦
AbrahamGreyson
2016-08-17 22:30:58 +08:00
这个和应用的执行流程关系不大的。

主要就像楼上的高手说的, 1 , 方便替换具体实现, 2 ,依赖于能力,而不是身份, 3 , 方便测试, 4 ,稍微一丁点提高编码效率。

你讲的是一个 app 常用的执行过程, 但是在一个中等规模的 app 中,这些流程只是基础设施, 你的业务代码会非常的多,对象之间的依赖会非常复杂,依赖注入能够让你开发速度更快, 修改具体实现的时候无需触碰业务代码。

new Service() 也是一种依赖注入,只不过是你手写的,而且无法注入接口,依赖注入更加灵活。
huijiewei
2016-08-17 23:19:39 +08:00
为了可以确定的测试,和未来无关
georgema1982
2016-08-18 03:53:31 +08:00
@sunsh217 把自己不懂的东西说成裝逼,本身就是裝逼的行为
coconne
2016-08-18 09:32:36 +08:00
更方便的面对接口编程
breeswish
2016-08-18 09:52:58 +08:00
个人观点:最重要的作用是可测试
repus911
2016-08-18 09:54:41 +08:00
@georgema1982 不要侮辱装逼
julyclyde
2016-08-18 11:10:11 +08:00
方便替换(也就方便了 mock )

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/299996

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX