Scala:在运行时替换方法

Scala: replace method at runtime

假设我有一个 class

class Original {
  def originalMethod = 1
}

现在,假设我有一个实例

val instance = new Original

现在是否可以在运行时对 instance 做一些事情来用不同的方法替换 originalMethod? (假设签名保持不变)

例如,现在调用instance.originalMethod时会调用下面的代码println("test"); 1

编辑 我不能打电话给 new Original。我只有它的现有实例,我必须对其进行修改。

编辑 2 (@Aleksey Izmailov 的回答)这是一个很好的解决方案,但并不是我想要的。我在测试方面考虑更多 - 编写 class "normally",而不是将函数指定为变量而不是方法

PS。我在尝试模仿 Mockito 间谍时偶然发现了这个问题

似乎你必须恢复到变异,因为你不能有新的实例并且行为必须改变。这可能是最简单的选项 (REPL):

将函数存储为可变字段:

scala> class Original {
     |   var originalMethod = () => 1
     | }
defined class Original

scala> val obj = new Original
obj: Original = Original@66ac5762

这是一个不带任何参数的函数,您需要对其调用 apply() 才能得到结果。

scala> obj.originalMethod
res0: () => Int = <function0>

scala> obj.originalMethod()
res1: Int = 1                       ^

用新函数替换它:

scala> obj.originalMethod = () => 2
obj.originalMethod: () => Int = <function0>

现在你有了新的行为:

scala> obj.originalMethod()
res2: Int = 2

有趣的是,您无法使用此 class 的通用版本进行默认实现,因为除非您将其更改为 Unit 或部分功能,否则您无法使用默认值。

这是它的通用版本:

scala> class Original[T] {                                                               
     |   var originalMethod: () => T = null                                              
     | }                                                                                 
defined class Original                                                                   

scala> val genImpl = new Original[Int] { originalMethod = () => 111 }                    
genImpl: Original[Int] = $anon@6b04acb2                                                       

scala> genImpl.originalMethod()                                                          
res8: Int = 111                                                                          

scala> genImpl.originalMethod = () => 222
genImpl.originalMethod: () => Int = <function0>

scala> genImpl.originalMethod()
res9: Int = 222

这在 JVM 上是不可能的 — 在 Java 或 Scala 中 — 不是您要求的方式。

参见例如In Java, given an object, is it possible to override one of the methods?

使用 Scala 而不是 Java 不会让您获得额外的优势,因为 类 和方法在 Scala 中的工作原理与 Java 相同。 (这样做是出于性能和互操作的原因。)