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

What is AOP, Dependency Injection and Inversion Of Control in Simple English

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

有人能用简单的英语解释吗?


我理解你的困惑,我花了一些时间来理解这些概念是如何联系在一起的。下面是我对这一切的(某种程度上是个人的)解释:

1。控制反转

控制反转是一个相当通用的设计原则,指行为规范与实际执行时的分离。例如,比较

1
myDependency.doThis();

具有

1
myDependency.onEventX += doThis();

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

2。依赖倒置

依赖倒置是另一个设计原则。粗略地说,它说高级抽象不应该直接依赖于较低级别的抽象;这实际上导致了一种设计,如果没有较低级别的抽象,就不能重用较高级别的抽象。

1
2
3
4
5
6
7
 class MyHighLevelClass {
     MyLowLevelClass dep = new MyLowLeverClass();
 }

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyLowLevelClass implements MyUsefulAbstraction { ... }

class MyHighLevelClass {

    MyUsefulAbstraction dep;

    MyHighLevelClass( MyUsefulAbstraction dep ) {
        this.dep = dep;
    }
}

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

注意,您不需要任何特殊的东西,比如容器来强制依赖倒置,这是一个原则。一本好的书是鲍勃叔叔的依赖倒置原理。

三。依赖注入

现在是依赖注入。对我来说,埃多克斯1〔2〕:

  • 依赖关系是从外部提供的,因此我们执行依赖倒置原则。
  • 容器设置依赖项(不是我们),所以我们说控制反转
  • 在我上面提供的示例中,如果使用容器来实例化对象并在构造函数中自动注入依赖项,则可以完成依赖项注入(我们经常谈到DI容器):

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

    注意,有各种形式的注射。还要注意,在这个透视图下,setter注入可以看作是回调的一种形式——DI容器创建对象,然后回调setter。有效地逆转了控制流。

    4。面向方面编程

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

    我不会在AOP上做更多的扩展。这里重要的是,依赖注入和AOP确实可以很好地一起工作,因为这使得编织非常容易。如果使用IOC容器和依赖项注入来抽象对象的实例化,则可以轻松地使用IOC容器在注入依赖项之前编织方面。否则,这将需要一个特殊的编译或一个特殊的ClassLoader

    希望这有帮助。


    依赖性注射在如何向5岁儿童解释依赖性注射方面解释得很好?:

    When you go and get things out of the
    refrigerator for yourself, you can
    cause problems. You might leave the
    door open, you might get something
    Mommy or Daddy doesn't want you to
    have. You might even be looking for
    something we don't even have or which
    has expired.

    What you should be doing is stating a
    need,"I need something to drink with
    lunch," and then we will make sure you
    have something when you sit down to
    eat.

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

    控制反转基本上意味着你没有一个控制一切的中心代码块(比如main()中的一个巨大的开关),而是有很多"不知何故"被调用的代码块。这个主题在维基百科上讨论:http://en.wikipedia.org/wiki/inversion-of-control


    依赖注入和控制反转之间的区别在

    http://martinfowler.com/articles/dipinwild.html网站

    (你是说依赖倒置,对吧?部分)

    总结:

    DI is about how one object acquires a dependency. When a dependency
    is provided externally, then the system is using DI.

    IoC is about who initiates the call. If your code initiates a call,
    it is not IoC, if the container/system/library calls back into code
    that you provided it, is it IoC.


    与"春季行动"的简单比较:

    Whereas DI helps you decouple your application
    objects from each other, AOP helps you decouple cross-cutting concerns from the
    objects that they affect.


    让我告诉你一些关于AOP的话,希望它能让你更容易理解。AOP最基本的原则是找到返回到代码中的许多地方不属于代码的概念业务。例如写入任何函数的每个入口,或在创建对象时将其打包,或在调用特定函数时向管理员发送电子邮件。因此,程序员将不再处理这些非业务方面的问题,而是从他们那里获取这些信息,我们在现场后处理这些方面。所有AOP的基础都在一条腿上……


    这三个都是不同的概念,但它们都能很好地协同工作,因此Spring应用程序经常同时使用所有这些概念。我给你举个例子。

    假设我们有一个可以做很多不同事情的Web应用程序。我们可以用许多方法构造这个应用程序,但有一种方法是创建一个类,负责完成这些事情中的每一件。我们需要从某个地方调用和创建这些类。一种选择是拥有一个大的主类,该类创建每个服务中的一个,打开一个套接字,并在这些服务进入时将调用传递给它们。不幸的是,我们已经去创造了一个上帝的类,它有太多的逻辑性,对我们程序中的每件事都知道得太多。如果我们更改了程序的任何内容,我们可能需要修改这个类。

    而且,很难测试。如果任何类围绕着实例化和直接调用其他类运行,我们就不能单独测试它。单元测试变得越来越难编写。

    解决这个问题的一种方法是使用控制反转。我们说"好吧,这些是服务班。谁任命他们?通常,每一个定义一个接口,比如LoginService或BillingService。该接口可能有多个实现,但您的应用程序不关心。它只知道它可以请求某种服务或具有某种名称的服务,它将得到一些好的回报。

    依赖注入允许我们将所有的小部件连接在一起。类具有可访问的字段、构造函数参数或setter方法,这些方法引用了它们需要访问的其他组件。这使得单元测试更加容易。您可以创建被测试的对象,向其抛出一个模拟或存根依赖项,然后测试对象在隔离状态下的行为是否正确。

    现在,我们真正的应用程序是一个复杂的混乱的部分,所有这些都需要这样连接在一起。有很多方法可以实现这一点,包括允许应用程序做出猜测("这个类需要一个用户服务,有一个其他的类,我负责实现用户服务"),或者通过仔细地解释它们是如何连接到XML或Java中的。Spring的核心是一个服务,负责将这些类连接在一起。

    现在我们到了AOP。让我们说,我们有所有这些类,它们以复杂的方式相互连接。我们可能想用非常一般的方式描述一些交叉关注点。例如,您可能希望在调用任何服务时启动数据库事务,并提交该事务,只要该服务不引发异常。事实证明,弹簧在执行这样的任务时处于一个独特的位置。Spring可以动态创建代理类,实现类所需的任何接口,并且可以将类包装在其代理中。现在,IOC和依赖注入当然不需要进行面向方面的编程,但这是一种非常方便的实现方法。