Groovy:Metaclass - 访问实例方法

时间:2013-09-04 18:35:09

标签: groovy metaclass

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

这是一个人为的例子:

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()

提前致谢

2 个答案:

答案 0 :(得分:1)

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”),我将使用命令模式 - 一个“命令”对象用于进食和不同树皮可以通过界面附着在任何动物身上。

  • 答案 1 :(得分: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>