PHP程序员如何理解IoC/DI

前端之家收集整理的这篇文章主要介绍了PHP程序员如何理解IoC/DI前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

<table class="PHP"><tr class="li1">
<td class="ln"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322

解决问题的根本 思想必须转换成习惯 构建一套完整的思想体系是开发能力成熟的标志 ——《简单之美》(前言)   “成功的软件项目就是那些提交产物达到或超出客户的预期的项目,而且开发过程符合时间和费用上的要求,结果在面对变化和调整时有弹性。” ——《面向对象分析与设计》(第版)P236 术语介绍   ——引用《Spring 技术手册》林信良   非侵入性 No intrusive   框架的目标之一是非侵入性(No intrusive) 组件可以直接拿到另一个应用或框架之中使用 增加组件的可重用性(Reusability) 容器(Container)   管理对象的生成、资源取得、销毁等生命周期 建立对象与对象之间的依赖关系 启动容器后,所有对象直接取用,不用编写任何一行代码来产生对象,或是建立对象之间的依赖关系。 IoC   控制反转 Inversion of Control 依赖关系的转移 依赖抽象而非实践 DI   依赖注入 Dependency Injection 不必自己在代码中维护对象的依赖 容器自动根据配置,将依赖注入指定对象 AOP   Aspectoriented programming 面向方面编程 无需修改任何一行程序代码,将功能加入至原先的应用程序中,也可以在不修改任何程序的情况下移除。 分层   表现层:提供服务,显示信息。 领域层:逻辑,系统中真正的核心。 数据源层:与数据库、消息系统、事务管理器及其它软件包通信。 ——《企业应用架构模式》P14 代码演示IoC   假设应用程序有储存需求,若直接在高层的应用程序中调用低层模块API,导致应用程序对低层模块产生依赖。   Business           __construct             FloppyWriter           save                   FloppyWriter     saveToFloppy                   Business 假设程序要移植到另一个平台,而该平台使用USB磁盘作为存储介质,则这个程序无法直接重用,必须加以修改才行。本例由于低层变化导致高层也跟着变化,不好的设计。   正如前方提到的   控制反转 Inversion of Control 依赖关系的转移 依赖抽象而非实践 程序不应该依赖于具体的实现,而是要依赖抽像的接口。请看代码演示   IDeviceWriter     saveToDevice   Business                   setWriter                       save                   FloppyWriter IDeviceWriter       saveToDevice                   UsbDiskWriter IDeviceWriter       saveToDevice                   Business UsbDiskWriter   FloppyWriter 控制权从实际的FloppyWriter转移到了抽象的IDeviceWriter接口上,让Business依赖于IDeviceWriter接口,且FloppyWriter、UsbDiskWriter也依赖于IDeviceWriter接口。   这就是IoC,面对变化,高层不用修改一行代码,不再依赖低层,而是依赖注入,这就引出了DI。   比较实用的注入方式有三种:   Setter injection 使用setter方法 Constructor injection 使用构造函数 Property Injection 直接设置属性 事实上不管有多少种方法,都是IoC思想的实现而已,上面的代码演示的是Setter方式的注入。   依赖注入容器 Dependency Injection Container   管理应用程序中的『全局』对象(包括实例化、处理依赖关系)。 可以延时加载对象(仅用到时才创建对象)。 促进编写可重用、可测试和松耦合的代码。 理解了IoC和DI之后,就引发了另一个问题,引用Phalcon文档描述如下:   如果这个组件有很多依赖, 我们需要创建多个参数的setter方法​​来传递依赖关系,或者建立一个多个参数的构造函数来传递它们,另外在使用组件前还要每次都创建依赖,这让我们的代码像这样不易维护   注册表中查找 Connection Session FileSystem Filter Selector   函数 SomeComponent     假设我们必须在应用的不同地方使用和创建这些对象。如果当你永远不需要任何依赖实例时,你需要去删掉构造函数的参数,或者去删掉注入的setter。为了解决这样的问题,我们再次回到全局注册表创建组件。不管怎么样,在创建对象之前,它增加了一个新的抽象层:   SomeComponent                 static factory               Connection         Session         FileSystem         Filter         Selector                 瞬间,我们又回到刚刚开始的问题了,我们再次创建依赖实例在组件内部!我们可以继续前进,找出一个每次能奏效的方法解决这个问题。但似乎一次又一次,我们又回到了不实用的例子中。   一个实用和优雅的解决方法,是为依赖实例提供一个容器。这个容器担任全局的注册表,就像我们刚才看到的那样。使用依赖实例的容器作为一个桥梁来获取依赖实例,使我们能够降低我们的组件的复杂性:   SomeComponent             __construct             _di           someDbTask               数据库连接实例                 _di             someOtherDbTask                               _di           方法也需要一个输入过滤的依赖服务         _di           Phalcon\DI   注册一个db服务     Connection                                       注册一个filter服务     Filter   注册一个session服务     Session   SomeComponent   Metask 这个组件现在可以很简单的获取到它所需要的服务,服务采用延迟加载的方式,只有在需要使用的时候才初始化,这也节省了服务器资源。这个组件现在是高度解耦。例如,我们可以替换掉创建连接的方式,它们的行为或它们的任何其他方面,也不会影响该组件。   参考文章   PHP程序员如何理解依赖注入容器dependency injection container httpPHP.com/zh/latest/reference/di.html What is Dependency Injection? Fabien Potencier Inversion of Control Containers and the Dependency Injection pattern by Martin Fowler 补充   很多代码背后,都是某种哲学思想的体现。   以下引用《面向模式的软件架构》卷模式系统第六章模式与软件架构   软件架构支持技术(开发软件时要遵循的基本原则)   抽象 封装 信息隐藏 分离关注点 耦合与内聚 充分、完整、简单 策略与实现分离 策略组件负责上下文相关决策,解读信息的语义和含义,将众多不同结果合并或选择参数值 实现组件负责执行定义完整的算法,不需要作出与上下文相关的决策。上下文和解释是外部的,通常由传递给组件的参数提供。 接口与实现分离 接口部分定义了组件提供的功能以及如何使用该组件。组件的客户端可以访问该接口。 实现部分包含实现组件提供的功能的实际代码,还可能包含仅供组件内部使用的函数和数据结构。组件的客户端不能访问其实现部分。 单个引用点 软件系统中的任何元素都应只声明和定义一次,避免不一致性问题。 分而治之 软件架构的非功能特性   可修改性 可维护性 可扩展性 重组 可移植性 互操作性 与其它系统或环境交互 效率 可靠性 容错:发生错误时确保行为正确并自行修复 健壮性:对应用程序进行保护,抵御错误的使用方式和无效输入,确保发生意外错误时处于指定状态。 可测试性 可重用性 通过重用开发软件 开发软件时考虑重用 原文链接:https://www.f2er.com/note/422683.html

猜你在找的程序笔记相关文章