Groovy探索之MOP 四 使用ExpandoMetaClass来实现Mixin

国内很多的文章都在说Groovy语言的Mixin机制就是Groovy语言的Categories机制。其实,在外面的Blog上,大量有人在讨论Groovy语言应该如何实现它自己的Mixin机制,这就是说明Groovy语言的Mixin机制还没有定型,处在讨论之中。Categories机制当然也能实现部分的Mixin功能,就像Java语言的接口机制,还有组合等等,都能实现部分的Mixin功能。就像C++语言的多继承一样,这些"古老"的机制都能或多或少的实现部分的Mixin功能。

其实,Mixin机制也没有想象的那么神秘和复杂。从字面上来看,它是由"mix"和"in"两个单词组成,它们各自的意义是"混合"和"进来",翻译过来就是把别的类的功能"混合进来"的意思。从这个意义上讲,上面所讲到的所有技术,如"多继承"、"接口"、"组合"和"Categories"都能实现这个机制的部分功能,也就是编译期的Mixin功能。

但是,现在的Mixin机制所强调的不仅是能够混入进别的类的功能,更强调的是要在运行期内能够混入别的类的功能。这就是那些"古老"技术所不能解决的。

在讨论中的Groovy语言的Mixin功能,不但要实现编译期的Mixin功能,同时也要实现运行期的Mixin功能。

虽然Groovy语言的Mixin机制还没有定型,但由于Groovy语言对MOP的良好支持,所以,我们还是可以比较方便的使用Groovy语言的MOP机制来实现运行期的Mixin功能的。

任何问题的讨论都是从一个简单的例子开始的。

比如,我们现在有一个Window类,它里面有一个简单的方法,就是能够实现开窗的动作。如下:

class Window
{
def open()
{
println 'the window is opened!'
}
}

同时,我们还有一个Human类,这个类可能会很复杂,但为了简单起见,我们现在不打算实现它的很多功能,只是简单的表示有这么一个类。如下:

class Human {

String name

}

现在,我们要操作的当然是Human的实例。本来这两个类是互不相关的,但现在Human的对象有了一个现实的要求,就是它需要能够实现"开窗"的动作。

当然,我们可以为Human类实现一个"openWindow"方法,但这一看就不符合面向对象设计的基本原则--类的功能要单一。

接下来的考虑是我们可以在Human类里使用Window类的"open"方法,这就要使用组合模式,也就实现了编译期的Mixin机制。但这种编译期的Mixin机制显然也太刚性了,可能我们在使用Human类的大多数场合都不会用到"openWindow"方法,却把它组合到Human类里。

最后,我们的考虑就是运行期的Mixin机制,这种实现肯定既实现了Mixin的功能,又抛弃了编译期的Mixin机制的弱点。

现在,我们就来实现运行期的Mixin机制,当然是借助于ExpandoMetaClass类的强大功能。

首先,我们来获取Window对象:

def window = new Window()

接着,我们要在运行期内借用该对象的"open"方法:

Human.metaClass.openWindow = window.&"open"

现在,我们就可以测试了:

def human = new Human()

human.openWindow()

运行的结果为:

the window is opened!

这就完成了一个简单的运行期的Mixin功能。

时间: 2024-10-31 14:36:30

Groovy探索之MOP 四 使用ExpandoMetaClass来实现Mixin的相关文章

Groovy探索之MOP 十五 方法名的动态性

到目前为止,我们的<Groovy探索之MOP>系列已经谈到了使用ExpandoMetaClass的方方面面,但值得注意的是,我们通过ExpandoMetaClass给一个类在运行期内添加一个方法,不管是普通方法还是静态方法,我们都是添加一个确定方法名的方法.即我们添加一个方法名为A的方法,然后才能使用这个方法A. 然而,方法名的动态性,其实是我们早已接触过的事情,比如在<Groovy探索之invokeMethod方法>里,我们就可以创建形如"sortByXxxxx()&q

Groovy探索之MOP 十二 方法的调用顺序

我们知道,除了使用hook来拦截方法以外,我们还可以通过各种方式来实现方法.如,我们可以在类里直接实现方法:我们可以通过ExpandoMetaClass在运行期内添加方法:我们还可以通过ExpandoMetaClass在运行期内单独给一个对象添加方法. 所有的这些直接添加方法的途径,如果存在hook的话,都是要被hook拦截的.所以,我们可以说,系统是优先调用hook的. 而hook的调用顺序,我们在上一篇<Groovy探索之MOP 十一 运行期内覆盖invokeMethod>已经谈到过了.

Groovy探索之MOP 十一 运行期内覆盖invokeMethod

我们很早就会使用Groovy语言的hook,即"invokeMethod"方法和其他的几个方法.我们会在一个类中实现"invokeMethod"方法,用来分派所有的或部分的在运行期内调用的该类实例的方法.这些我们在<Groovy探索之MOP 一 invokeMethod和methodMissing方法>已经详细的谈到过. 现在,我们已经深入的接触到了Groovy语言的MetaClass,更是也到处使用到了ExpandoMetaClass.我们都已经知道,

Groovy探索之MOP 十三 Interceptor 三(2)

其实,阻止拦截的使用像在<Groovy探索之MOP 十三 Interceptor 三(1)>中的最后一个例子那像的使用并不多,更多的是在使用拦截器的客户那里决定是否使用拦截器.还是上一篇的那个例子: class Hello { def hello(name) { "hello,$name" } } 我们现在明确的把类中所有的方法进行拦截,拦截器如下: class AllInterceptor implements Interceptor{ Object beforeInvo

Groovy探索之MOP 十 Interceptor 二

在本系列的<Groovy探索之MOP 九 Interceptor 一>中,我们已经详细的介绍了一个简单的拦截器类的方方面面,使得我们初步有了拦截器的基础.本篇需要在前面的拦截器类的基础上,进一步用拦截器类来实现我们的AOP编程. 首先,我们在本系列的第一篇中,所拦截的方法都是固定的方法.现在,我们需要把它扩展成由拦截器类的使用者来指定被拦截的方法. 先还是给出需要被拦截的类来: class Foo { def test1() { println 'test1' } def test2() {

Groovy探索之MOP 十四 对Java类使用Groovy语言的MOP

既然Groovy语言是Java语言的扩展,那么我们在使用Groovy语言的时候,就很难与Java语言真正脱得了干系,那怕我们是在做一个纯Groovy语言的项目,如Grails项目.我们可能在Groovy代码中会用到遗留的Java类和包:也可能是为了性能的原因,我们不得不在Groovy语言中使用到Java类:等等. 如果我们要对于Java类使用Groovy语言的MOP,比如我们想给一个Java类的对象在运行期内添加一个方法.那么我们该怎么办呢? 比如,我们有如下的一个Java类: //(Java代

Groovy探索之MOP 三 Class、MetaClass和ExpandoMetaClass

Class当然是Groovy语言从Java语言继承来的,这就是说Groovy语言也继承了Java语言的反射机制.这意味着我们能够像在Java语言里使用反射那样,在Groovy语言里写出诸如下面的代码: import java.lang.reflect.Method class Testor { def testDelegate() { 'ok' } static void main(args) { def t = new Testor() Class cls = t.class Method m

Groovy探索之MOP 一 invokeMethod和methodMissing方法

终于要谈到Groovy语言的MOP特性了,我在前面的章节中零星的谈到了它,却始终没有系统的来谈到它.这是因为Groovy语言的MOP特性实在是太灵活了,比如本章节要谈到的"invokeMethod"和"methodMissing"方法,它们的功能有很大的相似之处,而区别却相当的微妙.但是,不管怎么样,Groovy语言的MOP编程都是我们必须掌握的.而这个系列我没有计划多少个部分谈完,跟<Groovy探索之闭包>系列一样,探索一部分说一部分. 本节要谈到的

Groovy探索之MOP 七 运行期内的方法和属性分析

在Groovy语言里,运行期内的方法和属性分析有三种方式,它们分别是: 第一, 继承自Java语言的反射方式. 第二, 使用"respondsTo"和"hasProperty"方法. 第三, 使用"hasMetaMethod"和"hasMetaProperty"方法. 以上三种方法都能在运行期内分析某个方法或属性是否存在,相信我们看到这里,一定会想,它们之间是否有什么区别呢? 漫谈这三种运行期内的方法和属性分析方式以及它们之间