【问题标题】:Groovy: Metaclass - accessing instance methodsGroovy:元类 - 访问实例方法
【发布时间】:2013-09-08 09:39:56
【问题描述】:

我正在尝试使用元类访问实例的方法,但我收到属性不存在的错误。有没有办法访问在另一个类中声明的类的属性。

这是一个人为的例子:

class DogFood {
   def ft = 'food!'
   def foodType() { ft}
}

class Dog {
  def bark() { println "woof!" }

  DogFood df = new DogFood()
  def ft() { println df.foodType()} 

  def getDf() {
    df
  }
}

def doAction( animal, action ) {
  animal."$action"()
}


def rex = new Dog()

println rex.df.ft  //works

def barkString = "bark"

doAction( rex, barkString ) //works
doAction( rex, "df.ft") //doesn't work
doAction( rex, "getDf().ft") //does not work

有没有办法使用 Groovy 的元类方法访问 df.ftgetDf().getFt()

提前致谢

【问题讨论】:

  • 但是你在哪里使用过元类?所看到的只是 GStrings 游戏。

标签: groovy metaclass


【解决方案1】:

我认为您无法使用该符号访问字符串名称中带有. 的任何内容。不过,您可以使用Eval.x 来完成。

def doAction( animal, action ) {
    Eval.x(animal, 'x.' + action)
}

编辑: 另请注意,如果您正在执行用户输入,则此方法存在风险。您可以使用Eval 执行任意代码。例如,

groovy:000> foo = [bark: { println 'bark' }]
===> {bark=groovysh_evaluate$_run_closure1@db2e44d}
groovy:000> Eval.x(foo, 'x.bark()')
bark
===> null
groovy:000> Eval.x(foo, 'x.bark(); println "executing more code"')
bark
executing more code
groovy:000>

【讨论】:

  • 在这种情况下,必须使用def barkString = "bark()" 而不是bark
  • 是的,谢谢@dmahapatro。否则它会将"bark" 解释为一个属性。
  • 正确。大多数时候我对使用Eval 持怀疑态度。必须格外小心地使用它们。 :)
  • 谢谢-这似乎有效-但是执行需要很长时间-您知道原因吗?
【解决方案2】:

doAction(rex.getDF(), "ft") 应该可以工作,尽管这不是您所追求的。

你也可以在引号中建立任何你想要的东西,所以我认为是这样的:

"${doAction( rex, df.ft )}" 会起作用。

我相信您遇到的具体问题是“$action”语法明确引用了您正在调用的类的属性,因此您的组合内容似乎不起作用。

我相信如果 dfs="df" 和 fts="ft" 那么 rex."$dfs"."$fts" 可能有效,但你必须调整你的 doAction 方法..

---顺便说一句。

如果您只是想为自己或一个非常小的团队编写代码,那么您想要的解决方案类型很好,但总体而言,这并不是解决此问题的“好”方法我会尝试找到更好的模式。起初看起来很整洁,但是:

  • A) 不明显
  • B) 它会降低你的工具的功能(让 eclipse 找到“ft”方法的所有用途——它会错过这个)
  • C) 它将检查转移到运行时,这可以在编译时完成
  • D) 由于上述所有原因以及其他一些原因,可维护性较差。

    如果我为代码执行此操作,我必须长期处理,我会先尝试在纯 Java 中解决它,然后将该解决方案优化为 groovy。

    最明显的方式是你有一个所有动物都实现的eat()和bark()接口——你的代码通常可以选择直接调用哪一个。

    如果您无法确定您希望直接从代码中调用什么(例如,如果您希望用户键入“bark”),我会使用命令模式——一个用于吃的“命令”对象和一个不同的oen 表示可以通过接口连接到任何动物的树皮。

  • 【讨论】:

    • 比尔-谢谢。这样做的原因是因为我必须根据某些模板动态调用某些方法 - 即,一个用户可能选择一个只希望我在 bean 中打印 3 个字段的模板,而另一个用户可能想要打印所有现有字段- 并且有多个具有多个模板的 bean,我们将在未来添加更多模板和字段。所以 - 总体计划是从模板中获取字段,然后动态打印模板指定的字段。我们已经有了一个基于反射的解决方案——它很慢
    • groovy 解决方案不会更快——查看命令模式或类似的东西,它不使用任何反射并且应该仍然能够让你做你想做的事情直接(快速)
    猜你喜欢
    • 1970-01-01
    • 2015-07-09
    • 1970-01-01
    • 1970-01-01
    • 2017-05-12
    • 2021-06-03
    • 1970-01-01
    • 2016-05-20
    • 1970-01-01
    相关资源
    最近更新 更多