2014-11-21 46 views
1

我想一元編程轉換應用於一些我的課,讓我們加入printXxx方法,這樣說:在Groovy中有一個可重用的元類代碼的優雅方式是什麼?

class Person { 
    String name 
} 

def p = new Person() 
p.printName() // does something 

我有一個粗略的想法如何可以做到這一點,一旦我有一個元類:

Person.metaClass.methodMissing = { name, args -> 
    delegate.metaClass."$name" = { println delegate."${getPropName(name)}" } 
    delegate."$name"(*args) 
} 

現在我該如何將這段代碼變成一個可重複使用的「庫」?我想這樣做:

@HasMagicPrinterMethod 
class Person { 
    String name 
} 

class Person { 
    String name 

    static { 
    addMagicPrinters() 
    } 
} 

回答

0

定義要添加爲特徵

trait MagicPrinter {       
    void printProperties() { 
    this.properties.each { key, val -> 
     println "$key = $val" 
    } 
    }   
} 

那麼這種特質添加到一個類的行爲

class Person implements MagicPrinter { 
    String name 
} 

現在使用它!

new Person(name: 'bob').printProperties() 
+0

我使用聯合編譯,並且永遠不能使特徵在這種設置下工作(生成的存根文件無效)。另外,我不想要一個方法(printProperties),我想爲每個屬性(printName,printAge等)動態生成一個方法。 – 2014-11-21 15:06:54

0

你可以去一個混合的方法:

class AutoPrint { 
    static def methodMissing(obj, String method, args) { 
     if (method.startsWith("print")) { 
      def property = (method - "print").with { 
       it[0].toLowerCase() + it[1..-1] 
      } 
      "${obj.getClass().simpleName} ${obj[property]}" 
     } 
     else { 
      throw new NoSuchMethodException() 
     } 
    } 
} 

您可以用靜態塊混吧:

class Person { 
    static { Person.metaClass.mixin AutoPrint } 
    String name 
} 

def p = new Person(name: "john doe") 


try { 
    p.captain() 
    assert false, "should've failed" 
} catch (e) { 
    assert true 
} 

assert p.printName() == "Person john doe" 

或者與expandoMetaClass:

class Car { 
    String model 
} 

Car.metaClass.mixin AutoPrint 

assert new Car(model: "GT").printModel() == "Car GT" 

因爲7蒙特hs後來是新的'現在':-)

相關問題