面向方面编程与面向对象编程
Posted
技术标签:
【中文标题】面向方面编程与面向对象编程【英文标题】:Aspect Oriented Programming vs. Object-Oriented Programming 【发布时间】:2010-09-18 23:21:56 【问题描述】:与这里和全世界的大多数开发人员一样,多年来我一直在使用面向对象编程 (OOP) 技术开发软件系统。所以当我读到面向方面编程 (AOP) 解决了许多传统 OOP 无法完全或直接解决的问题时,我停下来想,这是真的吗?
我已经阅读了很多信息,试图了解这种 AOP 范式的关键,并且我在同一个地方,所以,我想更好地了解它在现实世界应用程序开发中的好处。
有人知道答案吗?
【问题讨论】:
所有答案都非常好,这是一个完美的案例,一个社区编辑的答案将它们结合在一起。所有人都在说同样的话,但以不同的方式并使用不同的例子来增加整体价值 【参考方案1】:为什么是“vs”?这不是“对”。您可以将面向方面的编程与函数式编程结合使用,也可以与面向对象的编程结合使用。不是“vs”,而是“面向方面编程with面向对象编程”。
对我来说,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 的一个方法并且这个类是包“com.company.*”的一部分,那么这是一个 set() 切入点。我们的第一个代码是“在运行任何设置切入点的方法后,运行以下代码”。
看看 AOP 是如何优雅地解决这里的问题的?实际上这里描述的一切都可以在编译时完成。 AOP 预处理器甚至可以在编译类本身之前修改您的源代码(例如,将 Display.update() 添加到每个设置切入点方法的末尾)。
然而,这个例子也显示了 AOP 的一大缺点。 AOP 实际上正在做一些许多程序员认为是“Anti-Pattern”的事情。确切的模式称为“Action at a distance”。
远距离的动作是 反模式(公认的常见 错误)其中一部分的行为 一个程序的变化很大 难以或不可能识别 在另一部分的操作 程序。
作为一个项目的新手,我可能只是阅读任何 set-method 的代码并认为它已损坏,因为它似乎没有更新显示。我并没有看到仅仅通过查看 set-method 的代码,在它被执行之后,一些其他代码将“神奇地”被执行以更新显示。我认为这是一个严重的缺点!通过对方法进行更改,可能会引入奇怪的错误。进一步了解代码的代码流,其中某些事情似乎可以正常工作,但并不明显(正如我所说,它们只是神奇地工作......不知何故),真的很难。
更新
澄清一下:有些人可能会觉得我说 AOP 是不好的东西,不应该使用。这不是我要说的! AOP 实际上是一个很棒的功能。我只是说“小心使用”。 AOP 只会在您将普通代码和 AOP 混用在同一个 Aspect 上时才会导致问题。在上面的示例中,我们具有更新图形对象的值并绘制更新后的对象的方面。这实际上是一个方面。将其中一半编码为普通代码,另一半编码为方面是增加问题的原因。
如果您将 AOP 用于完全不同的方面,例如对于日志记录,您不会遇到反模式问题。在这种情况下,该项目的新手可能想知道“所有这些日志消息来自哪里?我在代码中没有看到任何日志输出”,但这不是一个大问题。他对程序逻辑所做的更改几乎不会破坏日志设施,对日志设施所做的更改也几乎不会破坏他的程序逻辑——这些方面是完全分开的。使用 AOP 进行日志记录的优势在于,您的程序代码可以完全专注于做它应该做的任何事情,并且您仍然可以拥有复杂的日志记录,而不会让您的代码到处被数百条日志消息弄得一团糟。此外,当引入新代码时,神奇的日志消息将在正确的时间以正确的内容出现。新手程序员可能不明白他们为什么在那里或他们来自哪里,但由于他们会在“正确的时间”记录“正确的事情”,他可以愉快地接受他们在那里的事实并继续做其他事情.
因此,在我的示例中,AOP 的一个很好的用法是始终记录是否通过 set 方法更新了任何值。这不会创建反模式,也几乎不会导致任何问题。
有人可能会说,如果您可以轻易地滥用 AOP 来制造这么多问题,那么将其全部使用是个坏主意。然而,哪些技术不能被滥用?你可以滥用数据封装,也可以滥用继承。几乎所有有用的编程技术都可能被滥用。考虑一种编程语言非常有限,它只包含不能被滥用的功能;一种语言,其中功能只能按照最初打算使用的方式使用。这样的语言将非常有限,以至于它是否可以用于现实世界的编程也是值得商榷的。
【讨论】:
日志记录似乎是 AOP 不会导致远距离操作的一个具体示例。目前,***作为使用方面进行安全检查的示例,这确实使程序流程更易于理解。 @kizzx2:事实上,日志记录的重点是——这是迄今为止我看到的 AOP 的最佳示例,但对 AOP 了解不多。感谢分享! @Mecki,您的示例过于简化,不能反映一般用例。在您的示例中,Display.update
不接受任何参数。如果我们需要传入参数怎么办(例如,通常log
函数需要message
参数)?那么我们不是需要添加大量样板代码来以 AOP 方式进行操作吗?
@Pacerier 我的例子被简化了,因为 SO 不是一个教学论坛。我只是在回答提问者的问题,可能比必要的要详细得多。如果您想了解更多关于 AOP 的信息,请尝试阅读一些程序员文档,如果您有详细的问题,为什么不在这里提问呢?不,不在评论中,去创建一个新问题,因为 that 就是 SO 的全部内容。我相信有人能够在回复中消除您的疑虑。
@Pacerier 对不起,我没看懂你的意思。请参阅此处:***.com/a/8843713/15809 此代码记录对每个公共方法的每次调用,包括所有方法参数类型和值。你只写了一次,任何方法都添加了零样板代码,它只是答案中显示的代码。【参考方案2】:
面向方面的编程提供了一种很好的方式来实现横切关注点,如日志记录、安全性。 这些横切关注点是必须在许多地方应用但实际上与业务逻辑无关的逻辑片段。
您不应将 AOP 视为 OOP 的替代品,而应将其视为一个不错的附加组件 使您的代码更加简洁、松散耦合并专注于业务逻辑。
因此,通过应用 AOP,您将获得 2 个主要好处:
现在每个关注点的逻辑都在一个地方,而不是分散在代码库中。
类更简洁,因为它们只包含主要关注点(或核心功能)的代码,而次要关注点已移至方面。
【讨论】:
【参考方案3】:OOP 和 AOP 不是相互排斥的。 AOP 可以很好地补充 OOP。 AOP 尤其适用于向方法添加标准代码(如日志记录、性能跟踪等),而不会用此标准代码堵塞方法代码。
【讨论】:
【参考方案4】:我认为这个问题没有一般性的答案,但需要注意的一点是,AOP 并没有取代 OOP,而是添加了某些分解功能来解决所谓的专制主要成分 (1)(或横切关注点)。
在某些情况下,只要您能够控制用于特定项目的工具和语言,它肯定会有所帮助,但也会增加方面交互的复杂性以及对其他工具(如 @)的需求987654322@ 仍然了解您的程序。
Gregor Kiczales 曾在 Google Tech Talks 上就 AOP 进行过有趣的介绍性演讲,我建议观看:Aspect Oriented Programming: Radical Research in Modularity。
【讨论】:
【参考方案5】:首先,AOP 不会取代 OOP。 AOP 扩展了 OOP。 OOP 的思想和实践保持相关性。拥有一个好的对象设计可能会更容易通过方面进行扩展。
我认为 AOP 带来的想法很重要。我们需要想办法在程序中的不同类上实现横切关注点,而不必更改类本身。但我认为 AOP 最终将成为我们使用的其他工具的一部分,而不是单独的工具或技术。我们已经看到了这种情况。
Ruby 和 Python 等一些动态语言具有诸如 mixins 之类的语言结构,可以解决相同的问题。这看起来很像 AOP,但更好地集成在语言中。
Spring 和 Castle 以及其他一些依赖注入框架可以选择向它们注入的类添加行为。这是一种运行时编织的方式,我认为这有很大的潜力。
我认为您不必学习一个全新的范例来使用 AOP。这些想法很有趣,但正在慢慢被现有工具和语言所吸收。随时了解并试用这些工具。
【讨论】:
【参考方案6】:OOP主要用来组织你的业务逻辑,而AOP帮助组织你的非功能性的东西比如审计、日志记录、事务管理、安全等。
通过这种方式,您可以将业务逻辑与非功能性逻辑解耦,从而使代码更简洁。
另一个优点是您可以非常一致地应用建议(例如审计),而无需实现任何接口,这为修改提供了极大的灵活性,而无需触及业务逻辑。
这种方式很容易实现关注点分离和单一职责。
此外,当它只解决业务问题时,它很容易将业务逻辑从一个框架(例如 Spring)移植到其他地方(将来)
【讨论】:
【参考方案7】:AOP 是处理这个概念的一种新的编程范式。方面是实现应用程序的特定非功能部分的软件实体。
我认为这篇文章是开始面向方面编程的好地方: http://www.jaftalks.com/wp/index.php/introduction-to-aspect-oriented-programming/
【讨论】:
以上是关于面向方面编程与面向对象编程的主要内容,如果未能解决你的问题,请参考以下文章