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

我读了很多信息,试图学习这个 AOP 范式的关键,而且我也处于同样的境地,所以,我想更好地了解它在现实世界应用程序开发中的好处。

有人有答案吗?

有帮助吗?

解决方案

为什么要“对”呢?这不是“对抗”。您可以将面向方面编程与函数式编程结合使用,也可以与面向对象编程结合使用。它不是“vs”,而是“面向方面编程” 面向对象编程”。

对我来说,AOP 是某种“元编程”。AOP 所做的一切也可以在没有 AOP 的情况下通过添加更多代码来完成。AOP 只是让你省去编写这段代码的麻烦。

维基百科有这种元编程的最佳示例之一。假设您有一个带有许多“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.*);

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

看到这里AOP是如何优雅解决问题的了吗?实际上这里描述的所有事情都可以在编译时完成。AOP 预处理器可以只修改您的源代码(例如在编译类本身之前,将 Display.update() 添加到每个设置切入点方法的末尾。

然而,这个例子也显示了 AOP 的一大缺点。AOP实际上正在做一些许多程序员认为“反模式”。确切的模式称为“远距离行动".

距离的动作是一种反模式(一个公认的共同误差),在程序的一个部分中,基于难以或不可能识别程序另一部分中的操作的行为差异很大。

作为项目的新手,我可能只是阅读任何设置方法的代码并认为它​​已损坏,因为它似乎没有更新显示。我不 只需查看设置方法的代码,执行该方法后,将“神奇地”执行其他一些代码来更新显示。我认为这是一个严重的缺点!通过更改方法,可能会引入奇怪的错误。进一步理解代码的代码流程,其中某些事情似乎工作正常,但并不明显(正如我所说,它们只是神奇地工作......不知怎的),真的很难。

更新

只是为了澄清:有些人可能会有这样的印象:我是说 AOP 很糟糕,不应该使用。我不是这个意思!AOP 实际上是一个很棒的功能。我只是说“小心使用”。如果您将普通代码和 AOP 混合在一起,AOP 只会导致问题 方面. 。在上面的示例中,我们有更新图形对象的值并绘制更新的对象的方面。这实际上是一个方面。将其中一半编码为普通代码,将另一半编码为方面,这会增加问题。

如果您将 AOP 用于完全不同的方面,例如对于日志记录,您不会遇到反模式问题。在这种情况下,该项目的新手可能会想“所有这些日志消息来自哪里?我在代码中没有看到任何日志输出”,但这并不是一个大问题。他对程序逻辑所做的更改几乎不会破坏日志设施,而对日志设施所做的更改也几乎不会破坏他的程序逻辑——这些方面是完全分开的。使用 AOP 进行日志记录的优点是,您的程序代码可以完全集中精力做它应该做的事情,并且您仍然可以进行复杂的日志记录,而不会让您的代码被数百条日志消息弄乱。此外,当引入新代码时,神奇地,日志消息将在正确的时间以正确的内容出现。新手程序员可能不明白他们为什么在那里或者他们来自哪里,但是由于他们会在“正确的时间”记录“正确的事情”,他可以愉快地接受他们在那里的事实并继续做其他事情。

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

有人可能会说,如果你可以轻易地滥用 AOP 来制造这么多问题,那么全部使用它并不是一个好主意。然而,哪种技术不能被滥用呢?您可以滥用数据封装,可以滥用继承。几乎所有有用的编程技术都可能被滥用。考虑一种编程语言的局限性,它只包含不能被滥用的功能;一种语言,其中的功能只能按照最初的预期使用。这种语言的局限性如此之大,以至于它是否可以用于现实世界的编程还存在争议。

其他提示

OOP和AOP不是互斥的。 AOP可以很好地添加到OOP中。 AOP对于向方法添加标准代码(如日志记录,性能跟踪等)非常方便,而不会使用此标准代码堵塞方法代码。

面向方面的编程提供了一种很好的方法来实现日志记录,安全性等跨领域问题。 这些交叉概念是必须在许多地方应用的逻辑部分,但实际上与业务逻辑没有任何关系。

你不应该把AOP看作是OOP的替代品,更像是一个不错的附加组件 使您的代码更加干净,松散耦合并专注于业务逻辑。 因此,通过应用AOP,您将获得两个主要好处:

  1. 每个问题的逻辑现在都放在一个地方,而不是散布在整个代码库中。

  2. 类更清晰,因为它们只包含主要关注点(或核心功能)的代码,而次要问题已转移到方面。

我认为这个问题没有一般性的答案,但有一点需要注意的是,AOP不会替换 OOP,但会添加某些分解功能来解决所谓的暴政问题。主导作品 1 )(或横切关注点)。

在某些情况下,只要您掌握了用于特定项目的工具和语言,它肯定会有所帮助,但也会增加关于方面交互的新复杂程度以及对其他工具的需求,例如< a href =“http://www.eclipse.org/ajdt”rel =“nofollow noreferrer”> AJDT 仍然可以理解你的程序。

Gregor Kiczales曾经在Google Tech Talks上就AOP做了一个有趣的介绍性演讲,我建议观看:面向方面编程:模块化中的激进研究

首先,AOP不会取代OOP。 AOP扩展了OOP。 OOP的想法和实践保持相关。拥有一个好的对象设计可能会更容易扩展它与方面。

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

像Ruby和Python这样的动态语言有像mixin这样的语言结构来解决同样的问题。这看起来很像AOP,但更好地集成在语言中。

Spring和Castle以及其他一些依赖注入框架可以选择向它们注入的类添加行为。这是一种做运行时编织的方法,我认为这有很大的潜力。

我认为你不必学习使用AOP的全新范例。这些想法很有趣,但现在慢慢地被现有的工具和语言所吸收。随时了解并试用这些工具。

AOP是一种处理这一概念的新编程范例。一个方面是实现应用程序的特定非功能部分的软件实体。

我认为本文是面向方面编程的好地方: http://www.jaftalks.com/wp/的index.php /引入到面向方面的编程/

OOP 主要用于整理业务逻辑,而 AOP 有助于整理非功能性内容如审计,日志记录,交易管理,安全等

通过这种方式,您可以将业务逻辑与非虚构逻辑分离,从而使代码更清晰。

Otter的优势在于您可以非常一致地应用建议(示例审计),而无需实现任何可在不触及业务逻辑的情况下提供极大灵活性的界面

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top