Java 什么是AOP,简单英语中的依赖注入和控制反转
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2572158/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is AOP, Dependency Injection and Inversion Of Control in Simple English
提问by Rachel
I have tried to understand AOP, Dependency Injection and Inversion of Control SPRING related concepts but I am having hard time understanding it.
我试图理解 AOP、依赖注入和控制反转 SPRING 相关概念,但我很难理解它。
Can anyone explain this in simple English ?
谁能用简单的英语解释一下?
采纳答案by ewernli
I understand your confusion and it took me some time to understand how these concepts were related together. So here is my (somehow personal) explanation of all this:
我理解你的困惑,我花了一些时间来理解这些概念是如何关联在一起的。所以这是我对这一切的(某种程度上是个人的)解释:
1. Inversion of Control
1. 控制反转
Inversion of controlis a design principle rather generic that refers to the decoupling of the specification of a behavior from when it is actually executed. Compare for instance,
控制反转是一种相当通用的设计原则,指的是行为规范与实际执行时的分离。比较例如,
myDependency.doThis();
with
和
myDependency.onEventX += doThis();
In the latter, there is no direct invocationwhich is more flexible. In its general form, inversion of control relates to the observer pattern, events, or callbacks.
在后者中,没有更灵活的直接调用。在一般形式中,控制反转与观察者模式、事件或回调有关。
2. Dependency inversion
2. 依赖倒置
Dependency inversion is another design principle. Roughly speaking, it says that higher-level abstraction should not depend directly on lower-level abstractions; this results indeed in a design where higher-level abstraction can not be reused without the lower-level abstractions.
依赖倒置是另一个设计原则。粗略地说,它说更高层次的抽象不应该直接依赖于较低层次的抽象;这确实导致在没有较低级别抽象的情况下无法重用较高级别抽象的设计。
class MyHighLevelClass {
MyLowLevelClass dep = new MyLowLeverClass();
}
class App {
void main() { new HighLevelClass().doStuff(); }
}
Here, MyHighLevelClass
can not compile without access to MyLowLevelClass
. To break this coupling, we need to abstractthe low level class with an interface, and remove the direct instantiation.
在这里,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(); }
}
Note that you don't need anything special like a container to enforce dependency inversion, which is a principle. A good reading is The Dependency Inversion Principleby Uncle Bob.
请注意,您不需要像容器这样的特殊东西来强制执行依赖倒置,这是一个原则。一个很好的读物是Uncle Bob 的The Dependency Inversion Principle。
3. Dependency injection
3. 依赖注入
Now comes dependency injection. To me dependency injection = IoC + dependency inversion
:
现在是依赖注入。对我来说dependency injection = IoC + dependency inversion
:
- dependencies are provided externally so we enforce the dependency inversion principle
- the container sets the dependencies (not us) so we speak of inversion of control
- 依赖是外部提供的,所以我们强制执行依赖倒置原则
- 容器设置依赖项(不是我们)所以我们说控制反转
In the example I provided above, dependency injection can be done if a container is used to instantiate objects and automatically injectthe dependency in the constructor (we speak then frequently of DI container):
在我上面提供的示例中,如果使用容器实例化对象并在构造函数中自动注入依赖项(我们经常说 DI 容器),则可以完成依赖注入:
class App {
void main() { DI.getHighLevelObject().doStuff(); }
}
Note that there are various form of injections. Note also that under this perspective, setter injectioncan be seen as a form of callback -- the DI container creates the object then calls back the setter. The flow of control is effectively inverted.
请注意,有多种形式的注射。还要注意,在这个视角下,setter 注入可以看作是一种回调形式——DI 容器创建对象然后回调 setter。控制流被有效地反转。
4. AOP
4. AOP
Strictly speaking, AOP has little to do with the 3 previous points. The seminal paper on AOPis very generic and present the idea of weaving various sources together (possibly expressed with different languages) to produce a working software.
严格来说,AOP和前面的3点关系不大。关于 AOP的开创性论文非常通用,并提出了将各种来源(可能用不同语言表达)编织在一起以生成可工作软件的想法。
I won't expand more on AOP. What is important here, is that dependency injection and AOP do effectively plays nicely together because it makes the weaving very easy. If an IoC container and dependency injection is used to abstract away the instantiation of objects, the IoC container can easily be used to weave the aspects before injecting the dependencies. This would otherwise requires a special compilation or a special ClassLoader
.
我不会在 AOP 上做更多的扩展。这里重要的是,依赖注入和 AOP 确实可以很好地协同工作,因为它使编织非常容易。如果使用 IoC 容器和依赖项注入来抽象对象的实例化,则可以轻松地使用 IoC 容器在注入依赖项之前编织方面。否则,这将需要特殊的编译或特殊的ClassLoader
.
Hope this helps.
希望这可以帮助。
回答by Thorbj?rn Ravn Andersen
Dependency injection was explained very well in How to explain dependency injection to a 5-year-old?:
依赖注入在如何向 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.
当你自己去把东西从冰箱里拿出来时,你可能会引起问题。你可能把门开着,你可能会得到一些妈妈或爸爸不希望你拥有的东西。您甚至可能正在寻找我们甚至没有或已过期的东西。
你应该做的是陈述一个需求,“我午餐需要喝点东西”,然后我们会确保你坐下来吃饭的时候有东西。
AOP - Aspect Oriented Programming - basically means that the source you write is modified with other code, based on rules located ELSEWHERE. This means that you can e.g. say "as the first line of every method I want a 'log.debug("entering method()")' in a central place and each and every method you compile with that rule in place will then have that line included. The "aspect" is the name of looking on code in other ways than simply from first source line to last.
AOP - 面向方面编程 - 基本上意味着您编写的源代码根据位于 ELSEWHERE 的规则使用其他代码进行修改。这意味着您可以例如说“作为每个方法的第一行,我想要一个 'log.debug("entering method()")' 在一个中心位置,然后您使用该规则编译的每个方法都将具有包括那一行。“方面”是指以其他方式查看代码的名称,而不仅仅是从第一行源代码行到最后一行。
Inversion of Control basically means that you do not have a central piece of code controlling everything (like a giant switch in main()) but have a lot of pieces of code that "somehow" get called. The subject is discussed at Wikipedia: http://en.wikipedia.org/wiki/Inversion_of_control
控制反转基本上意味着您没有控制一切的中央代码(例如 main() 中的巨大开关),但有很多“以某种方式”被调用的代码。该主题在维基百科上进行了讨论:http: //en.wikipedia.org/wiki/Inversion_of_control
回答by Brandon Yarbrough
These three are all different concepts, but they all work well together, and so Spring apps often make use of all of it at once. I'll give you an example.
这三个都是不同的概念,但它们都可以很好地协同工作,因此 Spring 应用程序通常会同时使用所有这些概念。我给你举个例子。
Let's say that we have a web application that can do many different things. We could construct this application in many ways, but one way is to create a class that is in charge of doing each of these things. We need to invoke and create these classes from somewhere. One option is to have a big main class that creates one of each of these services, opens up a socket, and passes calls to these services as they come in. Unfortunately, we've gone and created ourselves a god class, which has way too much logic and knows way too much about how everything in our program works. If we change anything about our program, we're probably going to need to modify this class.
假设我们有一个可以做许多不同事情的 Web 应用程序。我们可以通过多种方式构建这个应用程序,但一种方式是创建一个类来负责完成这些事情中的每一个。我们需要从某个地方调用和创建这些类。一种选择是拥有一个大的主类来创建这些服务中的每一个,打开一个套接字,并在这些服务进来时将调用传递给这些服务。不幸的是,我们已经创建了一个神类,这有办法太多的逻辑,并且对我们程序中的所有内容的工作原理了解得太多。如果我们更改程序的任何内容,我们可能需要修改这个类。
Also, it's difficult to test. We can't test any class in isolation if it runs around instantiating and invoking the other classes directly. Unit tests become much, much harder to write.
此外,它很难测试。如果任何类围绕着实例化和直接调用其他类运行,我们就不能孤立地测试它。单元测试变得非常难以编写。
A way to get around this is to use inversion of control. We say "okay, these are service classes. Who instatiates them? Not me." Usually, each one defines an interface, like LoginService or BillingService. There might be more than one implementation of that interface, but your app doesn't care. It just knows that it can ask for a certain kind of a service or a service with a certain name, and it'll get something nice back.
解决这个问题的一种方法是使用控制反转。我们说“好吧,这些是服务类。谁来设置它们?不是我。” 通常,每个接口都定义了一个接口,例如 LoginService 或 BillingService。该接口的实现可能不止一种,但您的应用并不关心。它只知道它可以请求某种服务或具有特定名称的服务,它会得到一些不错的回报。
Dependency injection allows us to wire all of our litle pieces together. Classes have accessible fields, constructor arguments, or setter methods that are references to the other components that they'll need to access. That makes unit testing much easier. You can create the object under test, throw a mock or stub dependency at it, and then test that the object behaved correctly in isolation.
依赖注入允许我们将所有的小块连接在一起。类具有可访问的字段、构造函数参数或 setter 方法,它们是对它们需要访问的其他组件的引用。这使得单元测试更容易。您可以创建被测对象,向其抛出模拟或存根依赖项,然后测试该对象是否在隔离中正确运行。
Now, our real application is a complex jumble of pieces that all need to be wired together just so. There are many ways to accomplish this, including allowing the application to make guesses ("this class wants a UserService, there is exactly one other class I'm in charge of that implements UserService") or by carefully explaining how they wire together in XML or Java. Spring, at its core, is a service that takes care of wiring these classes together.
现在,我们真正的应用程序是一堆复杂的碎片,它们都需要如此连接在一起。有很多方法可以实现这一点,包括允许应用程序进行猜测(“这个类需要一个 UserService,我负责的另一个类实现了 UserService”)或通过仔细解释它们如何在 XML 中连接在一起或爪哇。Spring 的核心是一个负责将这些类连接在一起的服务。
Now we get to AOP. Let us say that we have all of these classes that are wired to each other in elaborate ways. There are some cross-cutting concerns that we might want to describe in very generic ways. For instance, perhaps you'd like to start a database transaction whenever any service is invoked, and commit that transaction so long as the service doesn't throw an exception. It turns out that Spring is in a unique position to perform such a task. Spring can create proxy classes on the fly that implement whatever interface your classes need, and it can wrap your class in its proxy. Now, IoC and dependency injection certainly aren't necessary to do aspect-oriented programming, but it's an extremely convenient way to accomplish it.
现在我们进入 AOP。假设我们拥有以精心设计的方式相互连接的所有这些类。我们可能想以非常通用的方式描述一些跨领域的关注点。例如,您可能希望在调用任何服务时启动数据库事务,并在服务不抛出异常的情况下提交该事务。事实证明,Spring 处于执行此类任务的独特位置。Spring 可以动态创建代理类来实现您的类需要的任何接口,并且它可以将您的类包装在其代理中。现在,IoC 和依赖注入对于面向方面的编程当然不是必需的,但它是一种非常方便的方式来完成它。
回答by Ziv.Ti
let me tell you some word about AOP, hope it make it simplier to understand. The very base principle of AOP is finding common tasks/aspects which returns in many places in the code and dont belong to the concerete business of the code. For example write to log on every entrance to any function, or when an object is created wrapp it, or send email to admin when calling to specific function. So instead of the programmers will handle these non businuss aspect we take it from them and we manage these aspects behond the scene. That all the basic of AOP on 1 leg....
让我告诉你一些关于 AOP 的词,希望它能让你更容易理解。AOP 的基本原则是找到在代码中的许多地方返回且不属于代码的具体业务的常见任务/方面。例如写入登录任何函数的每个入口,或者在创建对象时包装它,或者在调用特定函数时向管理员发送电子邮件。因此,与其让程序员处理这些非业务方面,不如从他们那里获取,我们在现场管理这些方面。一条腿上的所有 AOP 基础......
回答by TastyCode
A simple comparison from Spring in Action:
与 Spring in Action 的简单比较:
Whereas DI helps you decouple your application objects from each other, AOP helps you decouple cross-cutting concerns from the objects that they affect.
DI 帮助您将应用程序对象彼此分离,而 AOP 帮助您将横切关注点与它们影响的对象分离。
回答by Maxim Eliseev
The difference between Dependency Injection and Inversion of Control is explained very well in
依赖注入和控制反转之间的区别在
http://martinfowler.com/articles/dipInTheWild.html
http://martinfowler.com/articles/dipInTheWild.html
("You mean Dependency Inversion, Right?" section)
(“你的意思是依赖倒置,对吧?”部分)
The summary:
摘要:
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.
DI 是关于一个对象如何获取依赖项。当从外部提供依赖项时,系统正在使用 DI。
IoC 是关于谁发起呼叫的。如果您的代码发起调用,则不是 IoC,如果容器/系统/库调用回您提供的代码,则是 IoC。