2012-03-23 2 views
2

Я хотел бы создать простую оболочку, которая позволила бы использовать методы объектов в качестве свободного интерфейса. Я думал о методах перезаписи класса при создании, но это, похоже, не работает. Возможно ли это каким-то образом с помощью метафорирования?groovy generic fluent builder

У меня есть такой фрагмент кода до сих пор:

class FluentWrapper { 

    def delegate 

    FluentWrapper(wrapped) { 
     delegate = wrapped 

     delegate.class.getMethods().each { method -> 
      def name = method.getName() 
      FluentWrapper.metaClass."$name" = { Object[] varArgs -> 
       method.invoke(wrapped, name, varArgs) 
       return this 
      } 
     } 
    } 

    def methodMissing(String name, args) { 
     def method = delegate.getClass().getDeclaredMethods().find { it.match(name) } 
     if(method) { 

      method.invoke(delegate,name, args) 
      return FluentWrapper(delegate) 
     } 
     else throw new MissingMethodException(name, delegate, args) 
    } 

} 

Допуская пример Java класс:

class Person { 
    void setAge() 
    void setName() 
} 

я хотел бы быть в состоянии выполнить следующий фрагмент кода:

def wrappedPerson = new FluentWrapper(new Person()) 
wrappedPerson.setAge().setName() 

Я использую Groovy 1.6.7 для этого.

ответ

2

Это все Groovy, и я использую 1.8.6 (текущая последняя), но с учетом этого Person класса:

class Person { 
    int age 
    String name 

    public void setAge(int age) { this.age = age } 
    public void setName(String name) { this.name = name } 
    public String toString() { "$name $age" } 
} 

И это FluentWrapper класс:

class FluentWrapper { 

    def delegate 

    FluentWrapper(wrapped) { 
    delegate = wrapped 
    } 

    def methodMissing(String name, args) { 
    def method = delegate.getClass().declaredMethods.find { it.name == name } 
    if(method) { 
     method.invoke(delegate, args) 
     return this 
    } 
    else throw new MissingMethodException(name, delegate, args) 
    } 
} 

Тогда, вы должны быть в состоянии сделать:

def wrappedPerson = new FluentWrapper(new Person()) 

Person person = wrappedPerson.setAge(85).setName('tim').delegate 

и person должны иметь возраст и имя, указанное

+0

Отлично, поэтому использование новой версии - это то, что я должен был сделать :) Я проверю это в понедельник. –

+0

Это работало как шарм :) Спасибо. –

0

Я нахожу answer красиво, но вы не могли получить доступ к delegate методов @tim_yates возвращаемых значений (что-то одно обычно любит делать, даже для строителей в случае build() :)

Кроме того, если это WASN» t, предназначенный для Builder, но для объекта с цепляемым интерфейсом (например, для объектов, обернутых jQuery в JS), это будет серьезной проблемой.

Так что я бы поставил оболочку, как это:

class FluentWrapper { 

    def delegate 

    FluentWrapper(wrapped) { 
    delegate = wrapped 
    } 

    def methodMissing(String name, args) { 
    def method = delegate.getClass().declaredMethods.find { it.name == name } 
    if(method) { 
     def result = method.invoke(delegate, args) 
     return result != null ? result : this 
    } 
    else throw new MissingMethodException(name, delegate, args) 
    } 
} 

Примечание оператор Элвиса не подходит так как falsy значение никогда бы получить вернулся.

Конечно, это зависит от того, кто может узнать, способ связан с цепью или нет, но это может быть преодолено с помощью аннотаций метода, если это необходимо.

+0

Это на самом деле лучшее решение в случае классического свободного подхода строителя. Однако я бы не сделал этого, так как я хочу выполнять несколько функций, не беспокоясь о том, что выходит из обернутого объекта. Возможно, было бы неплохо объединить эти подходы и добавить некоторое значение конструктора, которое позволило бы решить, какое поведение предназначено для этой конкретной оболочки. –

Смежные вопросы