关于oop:面向方面编程与面向对象编程

Aspect Oriented Programming vs. Object-Oriented Programming

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

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

有人知道答案吗?


为什么"VS"?它不是"vs"。可以将面向方面编程与函数编程结合使用,也可以与面向对象编程结合使用。它不是"vs",而是"面向方面编程和面向对象编程"。好的。

对我来说,AOP是一种"元编程"。AOP所做的一切也可以在没有它的情况下通过添加更多的代码来完成。AOP只是为您节省了编写此代码的时间。好的。

维基百科有这个元编程的最好例子之一。假设您有一个图形类,其中包含许多"set…()"方法。每一种设置方法后,图形的数据都发生了变化,因此图形发生了变化,因此需要在屏幕上更新图形。假设要重新绘制图形,必须调用"display.update()"。经典的方法是通过添加更多的代码来解决这个问题。在您编写的每个集合方法的末尾好的。

1
2
3
4
5
void set...(...) {
    :
    :
    Display.update();
}

如果您有3个set方法,那不是问题。如果你有200个(假设的),在任何地方加上它都会变得非常痛苦。此外,每当添加新的set方法时,必须确保不要忘记将其添加到末尾,否则只会创建一个bug。好的。

AOP在不添加大量代码的情况下解决了这一问题,而是添加了一个方面:好的。

1
2
3
after() : set() {
   Display.update();
}

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

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

那是什么意思?这意味着,如果一个方法被命名为"set*"(*表示在set之后可能有任何名称),不管该方法返回什么(第一个星号)或者它需要什么参数(第三个星号),它是MyGraphicClass的一个方法,并且这个类是包"com.company.*的一部分,那么这是一个set()切入点。我们的第一个代码说"在运行了任何一个设置点的方法之后,运行下面的代码"。好的。

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

然而,这个例子也显示了AOP的一大缺点。AOP实际上做了许多程序员认为是"反模式"的事情。确切的模式称为"远距离行动"。好的。< Buff行情>

远处的动作是反模式(公认的共同点错误)其中一部分的行为程序的差异很大难以或不可能识别另一部分的操作程序。好的。< /块引用>

作为一个项目的新手,我可能只是阅读了任何set方法的代码,并认为它是坏的,因为它似乎不更新显示。我看不出仅仅通过查看set方法的代码,它执行之后,其他一些代码将"神奇地"执行以更新显示。我认为这是一个严重的缺点!通过对方法进行更改,可能会引入奇怪的错误。进一步理解代码流,其中某些东西看起来工作正常,但并不明显(如我所说,它们只是神奇地工作…不知何故),真的很难。好的。更新

只是为了澄清:有些人可能会有这样的印象,我说AOP是一个坏东西,不应该被使用。我不是这么说的!AOP实际上是一个很好的特性。我只是说"小心使用"。AOP只会在将正常代码和AOP混合在同一方面时引起问题。在上面的示例中,我们有更新图形对象的值和绘制更新对象的方面。这实际上是一个方面。将它的一半编码为普通代码,另一半编码为方面是增加问题的原因。好的。

如果将AOP用于完全不同的方面,例如用于日志记录,则不会遇到反模式问题。在这种情况下,项目的一个新手可能会想"这些日志消息是从哪里来的?"我在代码中没有看到任何日志输出",但这不是一个大问题。他对程序逻辑所做的更改不会破坏日志设施,对日志设施所做的更改也不会破坏他的程序逻辑——这些方面是完全分离的。使用AOP进行日志记录有一个优点,即程序代码可以完全集中精力做它应该做的事情,而且您仍然可以进行复杂的日志记录,而不会让代码被到处成百上千的日志消息杂乱无章。同样,当引入新代码时,日志消息会在正确的时间出现,并显示正确的内容。新手程序员可能不理解他们为什么会在那里,或者他们来自哪里,但是由于他们会在"正确的时间"记录"正确的事情",所以他可以很高兴地接受他们在那里的事实,然后继续做其他事情。好的。

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

有人可能会说,如果你可以轻易地滥用AOP来制造这么多问题,那么把它全部使用是一个坏主意。然而,哪些技术不能被滥用?您可以滥用数据封装,也可以滥用继承。几乎所有有用的编程技术都可以被滥用。考虑到编程语言的局限性,它只包含不可滥用的特性;一种特性只能按照最初预期的方式使用的语言。这样的一种语言是如此的有限,以至于如果它甚至可以被用于现实世界的编程,那么它是可以论证的。好的。好啊。


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

你不应该把AOP看作是OOP的替代品,更不要说它是一个很好的附加组件。使您的代码更加干净、松散耦合,并集中于业务逻辑。因此,通过应用AOP,您将获得2大好处:

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

  • 类更干净,因为它们只包含主要关注点(或核心功能)的代码,次要关注点已转移到方面。


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


    我认为这个问题没有一般的答案,但需要注意的一点是,AOP并不能取代OOP,而是增加了一些分解特性,以解决所谓的主导成分(1)的专制(或横切关注)。

    在某些情况下,只要您能够控制用于特定项目的工具和语言,它肯定会有所帮助,但同时也增加了一个新的复杂度,涉及到各个方面的交互,以及需要像AJDT这样的附加工具来仍然理解您的程序。

    GregorKiczales曾经在Google技术讲座上做了一个有趣的关于AOP的介绍性演讲,我建议大家看看:面向方面的编程:模块化的激进研究。


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

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

    像Ruby和Python这样的两种动态语言都有类似于mixin的语言结构,可以解决相同的问题。这看起来很像AOP,但在语言中集成得更好。

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

    我认为你不需要学习一个全新的模式来使用AOP。这些想法很有趣,但慢慢地被现有的工具和语言所吸收。只需随时了解并试用这些工具。


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

    我认为本文是从面向方面编程开始的好地方:http://www.jaftalks.com/wp/index.php/introduction-to-aspect-oriented-programming/