面向方面的编程 (AOP)是一种相当流行的编程范例。
维基百科的文章很好地解释了这种方法的动机。
AOP是用于全局概念的出色工具,例如:日志记录,它直接不影响代码的逻辑。
但是,将AOP用于诸如授权之类的业务需求时会发现问题。 这些方面应该在适当的代码中清晰可见,以便开发人员在阅读源代码时可以立即看到它们是否已正确实现。 AOP框架通常使用注释来解决此问题:
@RequireRole(Role.Admin)
但是,就可读性而言,使用
requireRole方法而不是注释与功能方法没有太大区别。
译者注 :在原始文章中,使用了以功能方式或功能方式 重写的表达式,可以将其解释为使用功能方式或直接/特定的函数调用。 本文包含可以用不同方式解释的示例。
另外:
1.将来,我们将回到高阶函数的概念
2.文章遇到了单词aspect,即英语主义和AOP 方面的概念
fun updateUserPermissions(…) { requireRole(Role.Admin)
此外,功能方法的优点是在决定需要哪个用户角色之前,可以扩展到更复杂的访问控制检查,例如方法参数分析。
其他类型的方面(例如事务)也是如此。 不幸的是,在功能上表示Java中更复杂的概念既麻烦又不方便,这在Java生态系统中导致了AOP框架的人为普及。
在Kotlin中,不是使用AOP和如下注释的类似Java的事务方法:
@Transactional fun updateUserPermissions(…) {
它也具有可读性,并且使用功能性方法重写时没有注解时看起来很干净。
fun updateUserPermissions(…) = transactional {
这种方法的优点是,您可以始终按Ctrl / Cmd +单击IDE中的
事务性函数声明,然后立即查看其确切功能。 这对于任何常用的AOP框架通常是不可能的。 即使使用IDE插件提供对方面代码的导航,其逻辑解密也需要了解单独的多功能API和/或约定。
不幸的是,在Kotlin中扩展替换AOP注释的方式存在问题。 对于将多个方面应用于同一个函数并带有花括号和缩进的情况:
fun updateUserPermissions(…) = logged { transactional {
一种解决方法是创建一个
高阶函数,以在应用多个方面时保留可接受的代码:
fun updateUserPermissions(…) = loggedTransactional {
功能方法的另一个缺点是诸如日志记录之类的方面需要访问方法参数。 通常可以通过特殊的API在AOP框架中使用它们,但是使用标准的Kotlin语言功能,您将无法轻松访问它们。 因此,为了以纯功能形式实际呈现日志记录方面的真实示例,您仍然需要编写大量的
样板代码 :
fun updateUserPermissions(params: Params) = logged("updateUserPermissions($params)") {
当您确实需要在应用程序中全局且一致地使用AOP时,这种考虑仍然使AOP成为首选的日志记录工具。 同时,鉴于Kotlin中提供了丰富的功能抽象,因此将AOP用于授权和事务之类的功能是一种滥用。 功能可以更好,更清洁地满足这些要求。
最后,我想说,进一步完善功能抽象以更好地替代AOP可能是Kotlin语言未来发展的有希望的载体。 基于Java的AOP框架通常是特定于JVM的,被认为是不可思议的,而Kotlin的功能抽象确实是跨平台的并且对用户透明。
译者注 :
1. 关于媒介(eng)的文章 。
2.原始文章的作者是Roman Elizarov (Team Lead JetBrains,研究Kotlin协程和库,体育编程/ ICPC,并发与算法,数学/定量金融;以前是Devexperts)。 在哈勃·埃利扎罗夫