2012-03-01 12 views
9

Tôi đã cố gắng để gỡ lỗi một số mã sử dụng mixin và tôi đã có thể làm giảm vấn đề của tôi xuống ví dụ này. Tôi có một lớp cha mẹ nhận các phương thức thông qua một mixin và một lớp con kế thừa từ cha mẹ. Nếu tôi cố gắng thay thế một phương thức trên một thể hiện của lớp con nó hoạt động UNLESS phương thức mà tôi đang thay thế được gọi trên một cá thể của lớp cha trước khi nó được thay thế. Nếu nó đã được gọi là sau đó tôi không thể thay thế nóGroovy đang làm gì ở đây?

Vì vậy, mã này:

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

sẽ mang lại:

foo

foo

Nhưng nếu bạn nhận xét ra dòng 13 (một trong những bình luận nói rằng để nhận xét nó ra), bạn sẽ nhận được:

chiến thắng

Tại sao điều này xảy ra? Tôi hy vọng có một số cách này có ý nghĩa trong bối cảnh của mô hình metaclass Groovy, nhưng tôi không nhận được nó.

Đây là Groovy 1.8.6

+1

tôi cũng có thể tái tạo điều này trong Groovy 1.8.4. Mùi như một lỗi đối với tôi; nhưng tôi không quá nhiều vào lập trình meta Groovy, vì vậy tôi không biết. – epidemian

+0

Cảm ơn bạn đã lưu ý, tôi chắc chắn sẽ bao gồm điều đó nếu tôi kết thúc việc gửi một lỗi lên đó. – mfollett

+0

Tôi muốn hỏi điều này trong danh sách gửi thư của người dùng groovy, có mùi giống như một lỗi đối với tôi ... –

Trả lời

3

Các metaclass được coi trên một phương pháp gọi và mixins có xử lý riêng của họ. Cả hai đều được nạp lazily, và tĩnh, nếu bạn không gọi một phương thức tải lười tĩnh không xảy ra.
Mixins được ưu tiên hơn ghi đè metaClass là lý do tại sao nó hiển thị foo và không thắng nếu bạn khởi tạo A.
Siêu meta được xác định trên đối tượng được áp dụng, để giải quyết cho mỗi lớp bạn cần Object.class .metaClass (tức là ở đây B.metaClass). Điều thú vị này sản lượng:

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) 

Xác định foo trên B khắc phục lỗi:

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

câu trả lời của bạn là Mixin ảnh hưởng đến metastore lớp, và các phương pháp lớp được ưu tiên hơn các phương pháp metastore đối tượng.

Proof:

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

Sản lượng:

foo 
class winning 

Một cách tiếp cận khác nhau

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

sản lượng

foo 
winning 
wat 
wat 
+0

bạn có nguồn nào bạn có thể trích dẫn cho thông tin này không? Tôi không hoàn toàn làm theo câu trả lời của bạn và tôi không thể tìm thấy bất kỳ thông tin nào về di sản của Groovy. – mfollett

+0

Tất cả điều này được lấy từ tài liệu và không sử dụng với giao diện điều khiển. Câu hỏi của bạn rất thú vị và xứng đáng là một bài đăng trên blog theo ý kiến ​​của tôi. Các trang Dynamic Groovy của tài liệu đã cung cấp một số câu trả lời http://groovy.codehaus.org/Per-Instance+MetaClass – Gepsens