什么是简单英语中的AOP,依赖注入和控制反转

我试图理解AOP,依赖注入和控制反转SPRING相关概念,但我很难理解它。

任何人都可以用简单的英语解释这一点吗?


答案 1

我理解你的困惑,我花了一些时间来理解这些概念是如何联系在一起的。因此,以下是我对所有这些的(以某种方式个人)解释:

1. 控制反转

控制反转是一种相当通用的设计原则,它指的是行为规范与实际执行时间的解耦。例如,比较,

myDependency.doThis();

myDependency.onEventX += doThis();

在后者中,没有更灵活的直接调用。在其一般形式中,控制反转与观察者模式事件回调有关。

2. 依赖关系反转

依赖关系反转是另一个设计原则。粗略地说,它说高级抽象不应该直接依赖于较低级别的抽象;这确实导致了一种设计,其中没有较低级别的抽象就无法重用高级抽象。

 class MyHighLevelClass {
     MyLowLevelClass dep = new MyLowLeverClass();
 }

 class App {
     void main() {  new HighLevelClass().doStuff(); }
 }

在这里,没有访问权限就无法编译。为了打破这种耦合,我们需要使用接口抽象出低级类,并删除直接实例化。MyHighLevelClassMyLowLevelClass

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

  1. 依赖关系在外部提供,因此我们强制执行依赖关系反转原则
  2. 容器设置依赖关系(不是我们),所以我们谈论控制反转

在我上面提供的示例中,如果使用容器来实例化对象并在构造函数中自动注入依赖项,则可以进行依赖关系注入(我们经常谈论DI容器):

 class App {
     void main() {  DI.getHighLevelObject().doStuff(); }
 }

请注意,有各种形式的注射。还要注意,在此角度下,setter 注入可以看作是一种回调形式 - DI 容器创建对象,然后回调 setter。控制流程有效地反转。

4. AOP

严格来说,AOP与前面的3点关系不大。关于AOP的开创性论文非常通用,并提出了将各种来源编织在一起(可能用不同的语言表示)以产生工作软件的想法。

我不会在AOP上进一步展开。这里重要的是,依赖注入和AOP有效地协同工作,因为它使编织变得非常容易。如果使用 IoC 容器和依赖关系注入来抽象出对象的实例化,则可以在注入依赖关系之前轻松地使用 IoC 容器来编织各个方面。否则,这将需要特殊的编译或特殊的.ClassLoader

希望这有帮助。


答案 2

依赖注入在如何向5岁的孩子解释依赖注入中得到了很好的解释:

当你自己去冰箱里拿出东西时,你可能会引起问题。你可能会把门打开,你可能会得到妈妈或爸爸不希望你拥有的东西。您甚至可能正在寻找我们甚至没有或已过期的东西。

你应该做的是陈述一个需求,“我需要一些东西在午餐时喝”,然后我们会确保你在坐下来吃饭时有东西。

AOP - 面向方面的编程 - 基本上意味着您编写的源代码根据位于其他地方的规则与其他代码一起修改。这意味着你可以说,例如,“作为每个方法的第一行,我希望在一个中心位置有一个'log.debug('enter method()')',然后你用该规则编译的每个方法都将包含该行。“方面”是以其他方式查看代码的名称,而不仅仅是从第一个源代码行到最后一个源代码行。

控制反转基本上意味着你没有一个控制一切的中心代码段(就像main()中的一个巨大的开关),但有很多代码片段“以某种方式”被调用。这个主题在维基百科上讨论:http://en.wikipedia.org/wiki/Inversion_of_control


推荐