在 Kotlin 中装饰方法集的惯用方法是什么

问题描述 投票:0回答:1

Python 程序员熟悉 java/kotlin 的静态编译世界就在这里。这是我试图解决的一个问题。我有一个网络服务客户端,它提供了许多与该服务交互的方法,如下所示:

class WebServiceClient {
  fun createUser(name: String, age: Int) {
    // Implementation
  }

  fun deleteUser(id: Int) {
    // Implementation
  }

  fun updateUser(id: Int, name: String, age: Int) {
    // Implementation
  }

  // And many more other methods
}

我想为其中一些方法添加日志记录功能。最直接的方法是显式修改每个方法:

...
  fun createUser(name: String, age: int) {
    log.info("before implementation")
    // Implementation
    log.info("after implementation")
  }
  
  fun deleteUser(id: Int) {
    log.info("before implementation")
    // Implementation
    log.info(after implementation")
  }
...

但是这种方法通常会引入重复、样板文件和混乱的方法业务逻辑以及一些不相关的东西(反AOP方法)。解决这个问题的另一种方法是装饰器,在 python 中很容易做到这一点,尽管我不知道如何在 Kotlin 中正确地做到这一点,而不引入重复并将日志逻辑与方法的业务逻辑分开。

我尝试提出一个接受客户端方法及其参数的高阶函数,它不完全是装饰器,但遵循不引入重复代码的想法。这是例子:

class WebServiceClient {
  fun createUser(name: String, age: Int) {
  }

  ...
  private fun <T> decorator(action: (vararg args: Any) -> T, vararg args: Any) : T {
    log.info("before action")
    val result = action(*args)
    log.info("after action")
    return result
  }
}

但是我最终遇到了一堆编译错误,例如:

  • 不支持[函数类型中参数的修饰符] - 对于操作类型定义中的 vararg
  • 扩展运算符 (*foo) 只能应用于可变参数位置 - 用于调用操作(*args)

要么没有办法在 Kotlin 中定义这样的泛型函数,要么我不知道如何正确使用 Kotlin 类型系统来定义它。而且,也许这根本不是 Kotlin 的方式。

我还没有深入研究注解和反射,因为定义这么简单的东西听起来太复杂了(回顾一下python的方法),但也许这是解决问题的唯一正确方向。

Kotlin 的方法是什么来解决我的问题,同时避免重复并遵循 AOP 原则(面向方面的编程)?

java kotlin compilation decorator aop
1个回答
0
投票

如果我理解正确的话,你只是想将日志逻辑提取到另一个函数中。

您的

decorator
方法即将完成。该方法实际上不需要接受任何参数,并且您可以
inline
整个事情,这样就不会实际创建 lambda 对象。它编译后的结果与您编写内联调用
log.info
完全相同。

private inline fun <T> withLogging(action: () -> T) : T {
    log.info("before action")
    val result = action()
    log.info("after action")
    return result
}

用途:

class User

class WebServiceClient {
    // here is a demonstration for a non-Unit method
    fun createUser(name: String, age: Int): User = withLogging {
        // create a user here...
        // you can access the name and age parameters here
        // withLogging returns whatever the lambda returns
        User()
    }
    
    // Unit methods work just as well
    fun doSomeSideEffect() = withLogging {
        println("Side effect")
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.