【问题标题】:Groovy Copying / Combining MetaMethods From Multiple ObjectsGroovy 复制/组合来自多个对象的元方法
【发布时间】:2016-06-10 14:29:44
【问题描述】:

我有两节课。在运行时,我想将一个对象的方法“克隆”到另一个对象。这可能吗?我使用 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-> x+1}" 之类的文本形式存在,它就可以工作,那么我就说 this.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

【问题讨论】:

  • 为什么要做这样的事情?你有什么要求? tbh,这看起来不是一个好主意
  • 是的,我广泛使用特征,这是一个多么了不起的功能。
  • 我想我明白你使用特征的原因。我可以利用 Traits 本机冲突处理来让第二个类覆盖第一个类。这可能行得通!只是从来没有使用过冲突处理,所以没想到用它来设计。
  • 请注意,当通过元类添加方法时,source 是闭包,而不是文本。因此,您可以将您的方法转换为某个类中的闭包属性。我还是会先尝试使用 trait。

标签: groovy metaclass metaobject


【解决方案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)

【讨论】:

  • 谢谢!实际上,对于我使用的特征,我也从未使用 withTraits 方法实现过,所以我会考虑这一点。在您的示例中,如果“MyClass”已经有一个 speak 方法,那么在这种情况下特征会覆盖吗?
  • 是的,使用withTraits,该方法将被覆盖
  • 我刚刚更新了原始帖子,提出了一个关于更动态地执行此操作的问题。如果可能的话,你能告诉我吗?或类似的东西?
  • 是的,它有效,我已将其添加到我的答案中,但 clientTrait 应该是 Class,而不是字符串
  • 抱歉,我觉得还是少了点什么。客户端名称以字符串形式出现。此客户端名称将成为特征名称的一部分。我们可以根据字符串动态指定要实现的特征名称吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-12-26
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-26
  • 1970-01-01
相关资源
最近更新 更多