Groovy从多个对象复制/组合MetaMethods

时间:2016-02-27 08:36:24

标签: groovy metaclass metaobject

我有两节课。在运行时,我想“克隆”一个对象的方法,而不是另一个。这可能吗?我使用leftshift失败的尝试如下所示。

(注意:我也尝试过使用相同结果的currMethod.clone()。)

class SandboxMetaMethod2 {
    String speak(){
        println 'bow wow'
    }
}

class SandboxMetaMethod1{

  void leftShift(Object sandbox2){
      sandbox2.metaClass.getMethods().each{currMethod->
          if(currMethod.name.contains("speak")){
              this.speak()
              this.metaClass."$currMethod.name" = currMethod
              this.speak()
          }
      }
  }

  String speak(){
    println 'woof'
  }
}

class SandboxMetaMethodSpec extends Specification {
    def "try this"(){
        when:
        def sandbox1 = new SandboxMetaMethod1()
        def sandbox2 = new SandboxMetaMethod2()
        sandbox1 << sandbox2


        then:
        true
    }

}


//Output
woof
speak
woof

按要求,我正在添加关于目标/用例的背景:

它非常类似于标准功能类型的用例。总之,我们在类上有很多方法适用于我们所有的客户端环境(50-100)。我们将这些应用于按特定默认顺序处理数据。这些方法中的每一个都可以被客户端特定的方法覆盖(如果它们以相同的方法名称存在),并且想法是使用上面的方法来“协调”方法集。根据客户端环境名称,我们需要一种动态覆盖方法的方法。

注意:元类的重写方法非常标准(或者我应该说,这就是存在惊人功能的原因)。如果我的方法存在像String currMethod =“{x-&gt; x + 1}”之类的文本,那么它就可以工作了,那么我只想说这个.metaClass。“$ currMethodName”= currMethod。在这种情况下我的挑战是我的方法被编译并存在于另一个类中,而不是在某个地方被定义为文本。

在构建时将所有自定义方法编译在特定于客户端的类中的目的是避免在运行时为每次计算编译这些动态方法的费用,因此所有特定于客户端的方法都被编译到单独的客户端中 - 特定的JAR在构建时。这种方式还允许我们仅将客户端特定的代码部署到相应的客户端,而不需要在某些主类中进行所有其他客户端计算。

我希望这是有道理的。

新方法,回应Jeremie B的建议:

由于我需要选择在运行时通过名称实现的特性,这样的工作会起作用:

String clientName = "client1"
String clientSpeakTrait = "${clientName}Speak"

trait globalSpeak {
    String speak() {
        println 'bow wow'
    }
}

trait client1Speak {
    String speak() {
        println 'woof'
    }
}

def mySpeaker = new Object().withTraits globalSpeak, clientSpeakTrait

1 个答案:

答案 0 :(得分:1)

Traits的基本示例:

trait Speak {
    String speak() {
        println 'bow wow'
    }
}

class MyClass {

}

def instance = new MyClass()
def extended = instance.withTraits Speak

extended.speak()

您可以选择在运行时使用哪种特性:

def clientTrait = Speak
def sb = new Object().withTraits(clientTrait)

sb.speak()

使用ClassLoader动态加载特征:

def clientTrait = this.class.classLoader.loadClass "my.package.${client}Speak"
def sb = new Object().withTraits(clientTrait)