Что здесь делает Groovy? - PullRequest
       21

Что здесь делает Groovy?

9 голосов
/ 02 марта 2012

Я пытался отладить некоторый код, который использует миксины, и мне удалось свести мою проблему к этому примеру. У меня есть родительский класс, который получает методы через mixin и дочерний класс, который наследуется от родителя. Если я пытаюсь заменить метод в экземпляре дочернего класса, он работает UNLESS , метод, который я заменяю, вызывался в экземпляре родительского класса перед его заменой. Если он был вызван, я не могу его заменить

Итак, этот код:

class M {
    protected foo() { println 'foo' }
}

@Mixin(M) class A {
 def bar() { foo() }
}

class B extends A {}

def b = new B()
def a = new A()
a.bar() //<-- comment out this line and see the difference
b.metaClass.foo = {println 'winning'}
b.bar()

даст:

Foo

Foo

Но если вы закомментируете строку 13 (ту, что содержит комментарий, в котором говорится, что она закомментирована), вы получите:

победа

Почему это происходит? Я ожидаю, что есть какой-то способ, который имеет смысл в контексте метаклассовой модели Groovy, но я не понимаю.

Это Groovy 1.8.6

1 Ответ

3 голосов
/ 16 марта 2012

Метакласс просматривается при вызове метода, а миксины имеют свой собственный обработчик.Оба загружаются лениво и статично, если вы не вызываете метод, статическая ленивая загрузка не происходит.
Миксины имеют приоритет над переопределениями метакласса, поэтому он отображает foo и не выигрывает, если вы инициализируете A.
Ameta определяется на объекте, к которому он применяется, для его разрешения для каждого класса вам необходим Object.class.metaClass (т.е. здесь B.metaClass).Интересно, что это приводит к:

groovy.lang.MissingMethodException: No signature of method: B.foo() is applicable for argument types: () values: []
Possible solutions: foo(), foo(java.lang.Object), bar(), any(), use([Ljava.lang.Object;), find(groovy.lang.Closure)

Определение foo на B устраняет ошибку:

class B extends A {
    def foo() { println 'not winning' }
}

Ваш ответ заключается в том, что Mixin влияет на метасторое класс, а методы класса имеют приоритет над методами метастазов объекта,

Доказательство:

@Mixin(M)
class B extends A {

}

a.bar() //<-- comment out this line and see the difference
B.metaClass.foo = {println 'class winning'}
b.metaClass.foo = {println 'object winning'}
b.bar()

Выход:

foo
class winning

Другой подход

class M {
    protected foo() { println 'foo' }
}

@Mixin(M) class A {
 def bar() { foo() }
}

class B extends A {
    def bar() { foo() }
}

class C extends B {
    def foo() { println 'wat' }
}

@Mixin(M)
class D extends C { }

def b = new B()
def a = new A()
def c = new C()
def d = new D()


a.bar() //<-- comment out this line and see the difference
b.metaClass.foo = {println 'winning'}
b.bar()

c.metaClass.foo = {println 'losing'}
c.bar()

d.metaClass.foo = {println 'draw'}
d.bar()

Выход

foo
winning
wat
wat
...