MOP总结

MOP 总结

之前介绍了基于 MOP 技术:

  • MOP——方法拦截
  • MOP——方法注入
  • MOP——方法合成

接下来对 MOP 的这三种技术的使用做一个汇总

在运行时创建类。

经过之前的讲解,我们可以发现,正是 MOP 的出现,使得 Groovy 变得非常灵活,可以改变已有类的结构,拦截或添加方法等,这为我们的开发工作提供了极大的便利性。既然可以扩展已有的类,那么我们也可以借助 MOP 来动态的创建一个类。这里需要借助 MOP 为我们提供的而一个类——Expando 类。

man = new Expando()
man.name = 'zx'
man.age = 18
man.work = { "working" }

println man
println man.work()

Expando 像是一个可以容纳任何属性的类,我们可以为其添加任意的属性,任意的方法(以闭包的形式),其实无论是属性,还是闭包,都被保存在 Expand 中的 Map 中,key 对应属性\闭包名,value 对应属性值,或者闭包体

关于拦截,注入,合成

经过之前三篇的学习,我们了解到,无论是拦截,注入,还是合成。每种技术都有若干实现方式。但是都不可避免的用到 MetaClass 这个类。拦截时,向其中注入了 invokeMethod 方法;合成时,向其中注入了 methodMissing 方法。注入的都是闭包,但是调用时如果找不到对应的方法,那么就会从闭包中找对应的名字,同时闭包的参数要和对应的方法相同。

  • 对于拦截,如果我们能修改类,就实现 GroovyInterceptable 接口,并实现 invokeMethod 方法;否则就在 ClassName.metaClass 上注入 invokeMethod
  • 对于合成,如果我们能修改类,就在类中重写 methodMissing 方法;否则就在 ClassName.metaClass 上注入 methodMissing
  • 对于注入,如果注入的方法在之前的类中已经实现过了,同时又在 ClassName.metaClass 上进行了注入,那么 metaClass 上的方法会优先执行。

相信到这里在看这幅图应该更容易理解:


image.png

一个综合应用

之前将的 MOP 的三大技术是分开来讲的,现在把这三个技术融合起来,实现这样一个场景,对于一个类,我们调用其方法,如果存在,就执行其本身的方法,如果不存在就进行方法合成。

class Man {
    def work(){
        "I can work"
    }
}

Man.metaClass.invokeMethod = {
    String name,args ->
        def method = Man.metaClass.getMetaClass(name,args)
        if(method){
            method.invoke(delegate,args)
        }else{
            Man.metaClass.invokeMissingMethod(delegate,name,args)
            //或者执行下面的方法,metaClass 中如果没有 invokeMethod 方法,那么会调用 metaClass 中的 methodMissing 方法,但是不如上面直接调用来的直观
            //Man.metaClass.invokeMethod(delegate,name,args)
        }
}

Man.metaClass.methodMissing = {
    String name,args ->
    def skills = ["run","sing","dance","talk"];

    if (skills.contains(name)){
        def impl = {
            Object[] vars ->
         "I can " + name
        }

        Man.metaClass."$name" = impl

        impl(args)
    }else{
        throw new MissingMethodException(name,Man.class,args)
    }

在这个例子中,首先使用拦截技术,将所有的方法调用拦截住(MetaClass 注入 invokeMethod 方法),然后分析本类是否可以执行该方法,如果可以路由给原本的方法,如果不可以那么执行合成(MetaClass 注入 methodMissing 方法)。

这里注意到一个细节:我们在方法合成之后,先将合成的方法注入到 MetaClass 中,这样在第二次调用的时候,就不会在此合成了,而是直接调用,大大提高的执行效率

你可能感兴趣的:(MOP总结)