我了解您的困惑,花了一些时间来了解这些概念如何相互关联。所以这是我对这一切的解释(某种程度上是个人的):
1.控制反转
控制反转是一种设计原则,而不是通用的,它是指行为规范与实际执行时的行为脱钩。比较一下
myDependency.doThis();
与
myDependency.onEventX += doThis();
在后者中, 没有直接调用 会更灵活。一般而言,控制反转与 观察者模式 , 事件 或 回调有关 。
2.依赖倒置
依赖倒置是另一种设计原则。粗略地说,它说较高级别的抽象不应直接依赖于较低级别的抽象。这确实导致了这样的设计:如果没有低层抽象,就不能重用高层抽象。
class MyHighLevelClass { MyLowLevelClass dep = new MyLowLeverClass(); } class App { void main() { new HighLevelClass().doStuff(); } }
在这里,
MyHighLevelClass无法访问无法编译
MyLowLevelClass。为了打破这种耦合,我们需要使用接口对低层类进行 抽象
,并删除直接实例化。
class MyLowLevelClass implements MyUsefulAbstraction { ... }class MyHighLevelClass { MyUsefulAbstraction dep; MyHighLevelClass( MyUsefulAbstraction dep ) { this.dep = dep; }}class App { void main() { new HighLevelClass( new LowLevelClass() ).doStuff(); } }
请注意,原则上不需要像容器之类的特殊功能来强制执行依赖关系反转。鲍勃叔叔的《依赖倒置原理》是一本好书。
3.依赖注入
现在是依赖注入。对我来说
dependency injection = IoC + dependency inversion:
- 依赖关系是从外部提供的,因此我们强制执行依赖关系反转原则
- 容器设置了依赖关系(不是我们),所以我们说的是控制反转
在上面我提供的示例中,如果使用容器实例化对象并自动 将 依赖项 注入 到构造函数中,则可以完成依赖项注入(我们常说DI容器):
class App { void main() { DI.getHighLevelObject().doStuff(); } }
请注意,有多种注射形式。还要注意,在这种情况下,setter注入可以看作是回调的一种形式-
DI容器创建对象,然后回调setter。控制流实际上是反向的。
4. AOP
严格来说,AOP与之前的3点无关。关于AOP的开创性论文非常笼统,提出了将各种来源(可能用不同的语言表示)编织在一起以产生有效软件的想法。
我不会在AOP上进行更多说明。这里重要的是,依赖项注入和AOP可以有效地很好地配合使用,因为它使编织非常容易。如果使用IoC容器和依赖项注入来抽象对象的实例化,则可以在注入依赖项之前轻松地使用IoC容器来编织方面。否则,这将需要特殊的编译或特殊的
ClassLoader。
希望这可以帮助。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)