Groovy08_MOP与元编程(方法拦截) ```

// java当中我们可以使用反射在运行的时候查看类的结构方法成员属性,
// 但是不能修改一个类的实现,不能动态的往类中去注入一个方法
// 而Groovy利用MOP元编程,可以做到这些,可以基于应用当前的状态,
// 动态的添加或者改变一些类的对象的方法和行为
// 比如一个类的一个方法我们没有写实现,可以通过服务器下发,吧这个方法的实现替换掉或者把里面的成员属性替换掉
// 由终端或者控制台服务器来操作这些行为

1. 第一种拦截方式

// 1. Person 是一个实现了GroovyObject的一个类
class Person{
    def name

    def dream(){
        println 'i have a dream'
    }
}

def p = new Person(name:'Zeking')

// 调用方法
p.dream()       // i have a dream
p.invokeMethod('dream',null)        // i have a dream

MetaMethod m = p.metaClass.getMetaMethod('dream',null)
m.invoke(p,null)         // i have a dream

println  '========================================================'
// 2. 进行拦截
// 实现GroovyInterceptable 接口 ,虽然这个接口没有任何的新增方法
// 但是我们实现了这个接口,我们在这个对象上调用任何方法
// 他会去调用到 invokeMethod  方法
class Person2 implements GroovyInterceptable{
    def name

    def dream(){
        println 'p2 i have a dream'
    }

    Object invokeMethod(String name, Object args){  // 这边成功进行了拦截
//        println 'inovoke'
        System.out.println 'p2 invoke'
    }
}

def p2 = new Person2(name:'Zeking')
p2.dream()      // Caught: java.lang.StackOverflowError
// 因为 Person2 实现了 GroovyInterceptable方法,所以当我们p2.dream()的时候
// 他不会去调用dream方法会去调用invokeMethod方法,而invokeMethod 被我们改变了行为,
// 行为是println 'inovoke' ,所以他不会去调用dream方法,而是调用println方法
// 又因为println 是 Grovvy 为我们注入到 Object 当中的 ,即为Person注入的方法,
// 而println 方法又会调用到invokeMethod 方法,所以层级太深了。我们可以用System.out.println 'invoke'

p2.dream1()     // 调用不存在的方法也会 调用到invokeMethod 方法,
println  '========================================================'

// 3. metaClass.invokeMethod 说明
class Person3 implements GroovyInterceptable{
    def name

    def dream(){
        System.out.println  'p3  i have a dream'
    }

    Object invokeMethod(String name, Object args){  // 这边成功进行了拦截
        System.out.println 'p3 invoke'
        //respondsTo(name) // 不能调用 respondsTo ,不然又会StackOverflowError
        // 那怎么判断这个类有么有实现 方法
        if (metaClass.invokeMethod(this,'respondsTo',name,args)){
            // 这是metaClass上面调用 invokeMethod方法 和在 Person3上面调用 invokeMethod方法有什么不一样的?
            // metaClass 是定义class的行为,而在Person3 是定义Person3类型的对象行为
            // metaClass 没有实现GroovyInterceptable 接口,是可以成功调用的

        }
    }
}


def p3 = new Person3(name:'Zeking')
p3.invokeMethod('dream',null)
// 没有实现GroovyInterceptable 接口 : p3 invoke ;
// 实现了GroovyInterceptable 接口:    p3 invoke
p3.metaClass.invokeMethod(p3,'dream',null)
// 没有实现GroovyInterceptable 接口 :p3  i have a dream
// 实现了GroovyInterceptable 接口:   p3  i have a dream
p3.dream()
// 没有实现GroovyInterceptable 接口 : p3  i have a dream
// 实现了GroovyInterceptable 接口:    p3 invoke

println  '========================================================'
// 4.
class Person4 implements GroovyInterceptable{
    def name

    def dream(){
        System.out.println  'p4  i have a dream'
    }

    Object invokeMethod(String name, Object args){  // 这边成功进行了拦截
        System.out.println 'p4 invoke'
        //respondsTo(name) // 不能调用 respondsTo ,不然又会StackOverflowError
        // 那怎么判断这个类有么有实现 方法
        if (metaClass.invokeMethod(this,'respondsTo',name,args)){
            metaClass.invokeMethod(this,name,null)
        }else {
            System.out.println 'p4 missing method'
        }
    }
}
def p4 = new Person4(name:'Zeking')
p4.dream()
// p4 invoke
// p4  i have a dream

println  '========================================================'

// 应用
class Manager {
    static Manager instance
    def isInit

    static Manager getInstance(){
        if (null == instance){
            synchronized (Manager.class){
                if (null == instance){
                    instance = new Manager()
                }
            }
        }
        return instance
    }

    def init(){
        isInit = true
    }

    def dream(){
        if (isInit){
            System.out.println  'm5  i have a dream'
        }
    }
}

class Manager2 implements  GroovyInterceptable{
    static Manager2 instance
    def isInit

    static Manager2 getInstance(){
        if (null == instance){
            synchronized (Manager2.class){
                if (null == instance){
                    instance = new Manager2()
                }
            }
        }
        return instance
    }

    def init(){
        isInit = true
    }

    def dream(){
        if (isInit){
            System.out.println  'm5  i have a dream'
        }
    }

    Object invokeMethod(String name, Object args){  // 这边成功进行了拦截
        System.out.println 'm2 invoke'
        if (name != 'init'){
            if(!isInit){
                System.out.println 'please invoke init first'
                return
            }
        }

        if (metaClass.invokeMethod(this,'respondsTo',name,args)){
            metaClass.invokeMethod(this,name,null)
        }else {
            System.out.println 'p4 missing method'
        }
    }
}

Manager2.instance.dream()
// p4 invoke
// please invoke init first


Manager2.instance.init()
Manager2.instance.dream()
// m2 invoke
// m2 invoke
// m5  i have a dream

2. 第二种拦截方式

// 1.第一种方式:在单个对象上进行方法拦截
// def zeking = new Zeking()  针对对象而不会对类产生影响
// 2.第二种方式: 在类上进行方法拦截
// Zeking.metaClass

println '==============1.1================================='

class Zeking{

    def dream(){
        println "Zekign's dream"
    }
}

// 1.1
def zeking = new Zeking()
zeking.dream()              // Zekign's dream
zeking.metaClass.dream = {  // 用一个闭包替换掉
    println 'replace dream'
}
zeking.dream()              // replace dream
new Zeking().dream()        // Zekign's dream

println '==============1.2================================='
// 1.2
class Zeking2{

    def dream(){
        println "2 : Zekign's dream"
    }
}
def zeking2 = new Zeking2()

zeking2.metaClass.dream = {  // 用一个闭包替换掉
    println '2 : replace dream'
}

// 如果我们覆盖了一个对象或者一个类的invokeMethod方法
// 那么它的实现就和 实现了GroovyInterceptable接口的类 一样了
// 不管调用了他的什么方法,都会调用到invokeMethod 里面去
zeking2.metaClass.invokeMethod = {
    String name, Object args->
        System.out.println('2 : invoke')
}

zeking2.dream()              // 2 : invoke

println '=============1.3=================================='
// 1.3
class Zeking3{

    def dream(){
        println "3 : Zekign's dream"
    }
}
def zeking3 = new Zeking3()

zeking3.metaClass.dream = {  // 用一个闭包替换掉
    println '3 : replace dream'
}

zeking3.metaClass.invokeMethod = {
    String name, Object args->
        System.out.println('3 : invoke')
        // metaClass  是谁的? 闭包默认的策略是Closure.OWNER_FIRST  (回去看lsn4)
        // 所以 这个闭包的OWNER 是 lsn8_1 的metaClass 不是 zeking3的 metaClass
        // 所以 不能自己使用metaClass 要使用代理
        // 默认的闭包他的 delegate 和 owner 是一样的
        // 但是 覆盖方法使用metaClass,他的 delegate会变成调用metaClass的对象或者类,即zeking3的
        def method = delegate.metaClass.getMetaMethod(name,args) // 用另一种方法,也可以继续使用 respondsTo
        if (method){
            method.invoke(delegate,args)
        }
}

zeking3.dream()              // 3 : invoke
                             // 3 : replace dream

println '=================1.4=============================='
// 1.4
//  不仅可以改变自己写的类 或者GDK的类,还可以改变 JDK的类

String.metaClass.plus = {
    CharSequence i ->
        i
}

println  "123"+'abc'        // abc

println '==============2.1================================='
// 2.1
class Zeking10{

    def dream(){
        println "10 : Zekign's dream"
    }
}
// 2.
def zeking10 = new Zeking10()
zeking10.dream()              // 10 : Zekign's dream
Zeking10.metaClass.dream = {  // 用一个闭包替换掉
    println '10 : replace dream'
}
zeking10.dream()              // 10 : Zekign's dream
new Zeking10().dream()        // 10 : replace dream

//println '==============================================='

3. propertyMissing methodMissing

// 1.propertyMissing  methodMissing
class Man{


    def propertyMissing(String name) {
        return null
    }

    def propertyMissing(String name, def arg) {

    }

    def methodMissing(String name, def args) {
        println 'methodMissing'
        return 'dream'  // 这个返回值是干嘛的,
    }

}

def man = new Man()
man.dream()             // methodMissing
println man.dream()     // methodMissing
                        // dream
// 如果在一个类上实现了 methodMissing 方法的话,
// 我们  在一个类上调用不存在的方法,他会为
// 我们 调用到 methodMissing 方法
// 成员属性就是propertyMissing

4. 模拟 命令行输入,动态改变方法

class Man2{

    def dream(){
        println 'Man2 dream()'
    }

    def propertyMissing(String name) {
        return null
    }

    def propertyMissing(String name, def arg) {

    }

    def methodMissing(String name, def args) {
        println 'methodMissing'
        return 'dream'  // 这个返回值是干嘛的,
    }

}

def man2 = new Man2()

def scanner = new Scanner(System.in)
Thread.start {
    while (true){
        def msg = scanner.nextLine()
        if (msg == 'exit'){
            break
        }

        if (man2.respondsTo(msg)){
            man2."$msg"()
        }else {
            def (name,body) = msg.split(":")
            man2.metaClass."$name" = {
                evaluate(body)
            }
        }
    }
}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值