面向方面的编程与面向对象的编程


199

像这里和全世界的大多数开发人员一样,多年来,我一直在使用面向对象编程(OOP)技术开发软件系统。因此,当我读到面向方面的编程(AOP)解决了传统OOP无法完全或直接解决的许多问题时,我停下来想一想,这是真的吗?

我已经阅读了很多信息,试图学习这种AOP范例的关键,并且我在同一地方,所以,我想更好地了解它在现实应用程序开发中的好处。

有人有答案吗?


7
所有答案都非常好,对于单个社区编辑的答案(将它们全部合并)而言,这是一个完美的案例。所有人都在说同一件事,但方式不同,并使用了不同的示例来增加总体价值
Vinko Vrsalovic

Answers:


323

为什么是“ VS”?它不是“ vs”。您可以将面向方面的编程与功能编程结合使用,也可以与面向对象的编程结合使用。它不是“ vs”,而是“使用面向对象编程面向方面的编程”。

对我来说,AOP是某种“元编程”。如果不添加AOP,只需添加更多代码即可完成所有操作。AOP可以节省您编写这段代码的时间。

Wikipedia拥有此元编程的最佳示例之一。假设您有一个带有许多“ set ...()”方法的图形类。在每种设置方法之后,图形的数据都会更改,因此图形也会更改,因此需要在屏幕上更新图形。假设要重新绘制图形,则必须调用“ Display.update()”。经典方法是通过添加更多代码来解决此问题。在每个set方法的最后,您编写

void set...(...) {
    :
    :
    Display.update();
}

如果您有3种设置方法,那不是问题。如果您有200个(假设的),那么将其添加到任何地方都会变得非常痛苦。同样,无论何时添加新的设置方法,都必须确保不要忘记将其添加到末尾,否则您将创建一个错误。

AOP无需添加大量代码即可解决此问题,而是添加一个方面:

after() : set() {
   Display.update();
}

就是这样!您不必告诉自己自己编写更新代码,而只是告诉系统在达到set()切入点之后,它必须运行该代码并将运行此代码。无需更新200种方法,无需确保您不会忘记在新的set-method上添加此代码。另外,您只需要一个切入点:

pointcut set() : execution(* set*(*) ) && this(MyGraphicsClass) && within(com.company.*);

那是什么意思?这意味着,如果一个方法被命名为“集*”(*表示集之后的任何名称可能跟随),无论什么样的方法返回(第一个星号),或者什么参数需要(第三星号)它MyGraphicsClass的方法此类是包“ com.company。*”的一部分,则这是set()切入点。我们的第一个代码说“ 运行任何设置切入点的方法,运行以下代码”。

在这里看到AOP如何优雅地解决问题?实际上,这里描述的所有内容都可以在编译时完成。AOP预处理程序甚至可以在编译类本身之前就可以修改您的源代码(例如,将Display.update()添加到每个set-pointcut方法的末尾)。

但是,此示例还显示了AOP的一大缺点。AOP实际上正在做许多程序员认为是“ 反模式 ”的事情。确切的模式称为“ 远距离动作 ”。

远距离操作是一种反模式(一种公认的常见错误),其中,程序的一个部分的行为基于难以或不可能识别程序的另一部分中的操作而急剧变化。

作为一个项目的新手,我可能只是阅读任何设置方法的代码,并认为它已损坏,因为它似乎不会更新显示内容。我仅通过查看设置方法的代码就看不到,它在执行后将“神奇地”执行一些其他代码来更新显示。我认为这是一个严重的缺点!通过更改方法,可能会引入奇怪的错误。进一步了解某些似乎正常工作但不明显的代码流(如我所说,它们只是神奇地工作……某种程度上),真的很难。

更新资料

只是为了澄清一下:有些人可能给我留下了印象,我说的是AOP不好,不应该使用。我不是那个意思 AOP实际上是一个很棒的功能。我只是说“小心使用”。仅当您将同一方面的常规代码和AOP混合使用时,AOP才会引起问题。在上面的示例中,我们具有更新图形对象的值并绘制更新后的对象的方面。这实际上是一个方面。将其中一半编码为普通代码,将另一半编码为方面是增加问题的原因。

如果您将AOP用于另一个完全不同的方面(例如,用于日志记录),则不会遇到反模式问题。在这种情况下,该项目的新手可能会想:“所有这些日志消息从何而来?我在代码中看不到任何日志输出”,但这不是一个大问题。他对程序逻辑所做的更改几乎不会破坏日志功能,而对日志功能所作的更改也几乎不会破坏其程序逻辑-这些方面是完全分开的。使用AOP进行日志记录的优点是您的程序代码可以完全专注于做应做的事情,并且仍然可以进行复杂的日志记录,而不会因到处都有数百条日志消息而使代码混乱。同样,当引入新代码时,神奇的日志消息将在正确的时间以正确的内容出现。

因此,在我的示例中,AOP的一种很好用法是始终记录是否已通过set方法更新任何值。这不会产生反模式,也几乎不会引起任何问题。

可能有人会说,如果您可以轻易地滥用AOP来创建许多问题,那么全部使用它是一个坏主意。但是,不能滥用哪种技术?您可以滥用数据封装,也可以滥用继承。几乎每一种有用的编程技术都可能被滥用。考虑一种有限的编程语言,以使其仅包含不可滥用的功能。一种仅在最初使用功能时才可以使用功能的语言。这样的语言将是如此有限,以至于它甚至可以用于现实世界的编程中,都是有争议的。


4
日志记录似乎是一个特定的示例,其中AOP不会导致“远距离操作”。这时,以Wikipedia为例,它使用方面来进行安全检查之类的事情,这的确使程序流程更加容易理解。
kizzx2 2010年

7
@ kizzx2:实际上,关于日志记录的要点很重要-这是到目前为止,我对AOP的实力所了解的最好的例子,而对AOP并不了解。感谢分享!
失误

@Mecki,您的示例过于简化,无法反映一般用例。在您的示例中,Display.update不接受任何参数。如果我们需要传递参数(例如,通常一个log函数需要一个message参数)怎么办?然后,我们是否不需要添加大量样板代码来执行AOP方法?
Pacerier 2014年

3
@Pacerier因为SO不是教学论坛,所以我的示例得到了简化。我只是在回答提问者的问题,可能比必要的问题要详细得多。如果您想了解有关AOP的更多信息,请尝试阅读一些程序员文档,如果您有详细的问题,为什么不在这里问呢?不,不是在评论中,而是提出一个新问题,因为就是SO的全部含义。我敢肯定,有人可以消除您的疑惑。
Mecki 2014年

2
@Pacerier抱歉,但是我看不到你的意思。参见此处:stackoverflow.com/a/8843713/15809此代码记录对每个公共方法的每次调用,包括所有方法参数类型和值。您只需编写一次,并且任何方法中都添加了零样板代码,这只是答案中显示的代码。
Mecki 2014年

29

面向方面的制图提供了一种很好的方式来实现横切关注点,例如日志记录,安全性。这些跨领域的概念是必须在许多地方应用的逻辑,但实际上与业务逻辑没有任何关系。

您不应将AOP视为OOP的替代品,而不应将其视为一个不错的附加组件,它可以使您的代码更清晰,松耦合,并专注于业务逻辑。因此,通过应用AOP,您将获得2大好处:

  1. 现在,每个关注点的逻辑都放在一个地方,而不是分散在整个代码库中。

  2. 类更干净,因为它们仅包含针对其主要关注点(或核心功能)的代码,而次要关注点已移至各个方面。


27

OOP和AOP不互斥。AOP可以很好地添加到OOP中。AOP在将标准代码(例如日志记录,性能跟踪等)添加到方法而不会用该标准代码阻塞方法代码时特别方便。


10

我认为对这个问题没有普遍的答案,但是要注意的一件事是,AOP不能代替 OOP,而是增加了一些分解功能,可以解决所谓的主要成分专制1)(或横切关注点)。

只要您控制着用于特定项目的工具和语言,它肯定会在某些情况下有所帮助,而且还增加了方面交互方面的新高度复杂性,以及仍需要了解AJDT等其他工具的需求您的程序。

Gregor Kiczales曾经在Google Tech Talks上进行过有关AOP的有趣介绍性演讲,我建议观看:面向方面的编程:模块化的基础研究


8

首先,AOP不会替代OOP。AOP扩展了OOP。OOP的思想和实践保持相关性。拥有良好的对象设计可能会使其更容易扩展方面。

我认为AOP带来的想法很重要。我们需要找到一种方法来实现程序中不同类的跨领域关注,而不必自己更改类。但是我认为AOP最终将成为我们使用的其他工具的一部分,而不是单独的工具或技术。我们已经看到了这种情况。

像Ruby和Python这样的几种动态语言具有像mixin这样的语言构造,可以解决相同的问题。这看起来很像AOP,但是更好地集成了该语言。

Spring和Castle以及其他几个依赖注入框架具有将行为添加到他们注入的类的选项。这是进行运行时编织的一种方式,我认为这具有很大的潜力。

我认为您不必学习全新的范例即可使用AOP。这些想法很有趣,但是逐渐被现有工具和语言所吸收。只要保持了解情况并尝试使用这些工具即可。



1

我这个问题迟到了,但它是我最喜欢的话题之一,所以让我分享我的看法。

OOP主要用于组织业务逻辑,AOP 帮助组织诸如审计,日志记录,事务管理,安全性等非功能性事务

这样,您可以将业务逻辑与非虚构逻辑分离,从而使代码更整洁。

其他的好处是您可以非常一致地应用建议(例如审计),而无需实现任何接口,这为修改提供了极大的灵活性,而无需涉及业务逻辑

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.