oop - 面向方面编程与面向对象编程

标签 oop aop paradigms

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

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

有人有答案吗?

最佳答案

为什么是“对”?这不是“对”。您可以将面向方面编程与函数式编程结合使用,也可以与面向对象编程结合使用。它不是“vs”,而是“面向方面的编程 面向对象的编程”。
对我来说,AOP 是某种“元编程”。 AOP 所做的一切也可以在没有它的情况下通过添加更多代码来完成。 AOP 只是节省了您编写此代码的时间。
维基百科拥有这种元编程的最佳例子之一。假设您有一个带有许多“set...()”方法的图形类。每次设置方法后,图形的数据都发生了变化,因此图形发生了变化,因此需要在屏幕上更新图形。假设要重新绘制图形,您必须调用“Display.update()”。经典的方法是通过添加更多代码来解决这个问题。在您编写的每个 set 方法的末尾

void set...(...) {
    :
    :
    Display.update();
}
如果您有 3 个设置方法,那不是问题。如果您有 200 个(假设的),那么在任何地方添加它会变得非常痛苦。此外,每当您添加新的 set-method 时,您必须确保不要忘记将其添加到最后,否则您只是创建了一个错误。
AOP 无需添加大量代码即可解决此问题,而是添加一个方面:
after() : set() {
   Display.update();
}
就是这样!无需自己编写更新代码,您只需告诉系统在到达 set() 切入点后,它必须运行此代码并且它将运行此代码。无需更新 200 个方法,无需确保不会忘记在新的 set-method 上添加此代码。此外,您只需要一个切入点:
pointcut set() : execution(* set*(*) ) && this(MyGraphicsClass) && within(com.company.*);
这是什么意思?这意味着如果一个方法被命名为“set*”(* 意味着任何名称都可以跟在 set 之后),无论该方法返回什么(第一个星号)或它采用什么参数(第三个星号),并且它是 MyGraphicsClass 的一个方法,这class 是包“com.company.*”的一部分,那么这是一个 set() 切入点。我们的第一个代码说“在运行任何设置切入点的方法之后,运行以下代码”。
看看这里 AOP 是如何优雅地解决问题的?实际上这里描述的一切都可以在编译时完成。 AOP 预处理器甚至可以在编译类本身之前修改您的源代码(例如,将 Display.update() 添加到每个 set-pointcut 方法的末尾)。
然而,这个例子也显示了 AOP 的一大缺点。 AOP 实际上正在做许多程序员认为是“ Anti-Pattern ”的事情。确切的模式称为“Action at a distance”。

Action at a distance is an anti-pattern (a recognized common error) in which behavior in one part of a program varies wildly based on difficult or impossible to identify operations in another part of the program.


作为项目的新手,我可能只是阅读了任何设置方法的代码并认为它​​已损坏,因为它似乎没有更新显示。我不只需查看 set-method 的代码,在它执行后,其他一些代码将“神奇地”执行以更新显示。我认为这是一个严重的缺点!通过对方法进行更改,可能会引入奇怪的错误。进一步理解代码的代码流,其中某些事情似乎可以正常工作,但并不明显(正如我所说,它们只是神奇地工作......不知何故),真的很难。
更新
澄清一下:有些人可能会觉得我说 AOP 很糟糕,不应该使用。这不是我要说的! AOP 实际上是一个很棒的特性。我只是说“小心使用”。如果您将普通代码和 AOP 混合用于同一 Aspect,AOP 只会导致问题。在上面的例子中,我们有更新图形对象的值和绘制更新对象的方面。这实际上是一个方面。将其中一半编码为普通代码,将另一半编码为方面是增加问题的原因。
如果您将 AOP 用于完全不同的方面,例如对于日志记录,您不会遇到反模式问题。在这种情况下,项目的新手可能想知道“所有这些日志消息从何而来?我在代码中没有看到任何日志输出”,但这不是一个大问题。他对程序逻辑所做的更改几乎不会破坏日志设施,而对日志设施所做的更改几乎不会破坏他的程序逻辑——这些方面是完全分开的。使用 AOP 进行日志记录的优势在于,您的程序代码可以完全专注于做它应该做的任何事情,并且您仍然可以拥有复杂的日志记录,而不会让您的代码被数百条日志消息杂乱无章。此外,当引入新代码时,神奇的日志消息将在正确的时间以正确的内容出现。新手程序员可能不明白他们为什么在那里或他们来自哪里,但由于他们会在“正确的时间”记录“正确的事情”,他可以很高兴地接受他们在那里的事实并继续做其他事情.
因此,在我的示例中,AOP 的一个很好的用法是始终记录是否通过 set 方法更新了任何值。这不会产生反模式,也几乎不会导致任何问题。
有人可能会说,如果您可以轻松地滥用 AOP 来制造如此多的问题,那么全部使用它是个坏主意。然而,哪些技术不能被滥用?你可以滥用数据封装,也可以滥用继承。几乎所有有用的编程技术都可能被滥用。考虑一种非常有限的编程语言,它只包含不能被滥用的功能;一种语言,其中功能只能按最初打算使用的方式使用。这种语言非常有限,以至于它甚至可以用于现实世界的编程是有争议的。

关于oop - 面向方面编程与面向对象编程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/232884/

相关文章:

c# - 调车场算法建模

c# - 我没有源代码的程序集上的 PostSharp

java - Spring in Action 3 AOP引发问题的例子

oop - 面向对象编程的替代方案?

php - 在 PHP 中将函数作为另一个函数的参数传递

java - java中如何在不传递指向该对象的指针的情况下从其他对象访问特定对象?

java - 在 JSF 应用程序中使用 Spring AOP

ruby - 在 Ruby 中用队列代替方法链,用规则代替条件

Javascript 对象方法范围 - 方法失败