【Groovy】MOP 元对象协议与元编程 ( 方法委托 | 批量方法委托 )

简介: 【Groovy】MOP 元对象协议与元编程 ( 方法委托 | 批量方法委托 )

一、批量方法委托


在上一篇博客 【Groovy】MOP 元对象协议与元编程 ( 方法委托 | 正常方法调用 | 方法委托实现 | 代码示例 ) 中 , 将 StudentManager 对象的方法委托给了其内部的 student1 和 student2 成员 , 在 methodMissing 方法中进行方法委托 , 需要使用 student.respondsTo(name, args) 代码 , 逐个判断调用的方法是否在 student1 或 student2 成员中 ; 如果 StudentManager 中定义了很多成员 , 那么就需要逐个进行判定 , 写起来很繁琐 ;


下面介绍一种实现方法委托的方式 , 可以优雅的处理上述问题 ;


在 StudentManager 中实现

def delegate(Class... classes)

方法 , 方法接收可变长度的 Class 对象作为参数 ;


首先 , 通过反射 , 创建委托对象 ;

def objects = classes.collect{
            // 通过反射创建要委托的对象
            it.newInstance()
        }


然后 , 通过 HandleMetaClass 注入 methodMissing 方法 ;

// 注入方法需要获取 org.codehaus.groovy.runtime.HandleMetaClass 对象进行注入
        StudentManager sm = this
        sm.metaClass.methodMissing = {
            String name, def args ->
  }


再后 , 在 objects 数组中查找哪个对象中包含 name(args) 方法 , 返回该对象赋值给 object 对象 ; 该步骤确保被代理类中有指定的方法 ;

// 在 objects 数组中查找哪个对象中包含 name(args) 方法
                // 返回该对象赋值给 object 对象
                def object = objects.find{
                    it.respondsTo(name, args)
                }


最后 , 如果最终找到的 object 方法不为空 , 则向 StudentManager 中注入相应方法 , 然后调用该注入的方法 ;

if (object) {
                    // 注入 name 方法
                    sm.metaClass."$name" = {
                        object.invokeMethod(name, it)
                    }
                    // 调用刚注入的方法
                    invokeMethod(name, args)
                }


方法委托实现如下 :


class StudentManager{
    {
        // 代码块中调用 delegate 方法 , 传入要委托的类
        delegate(Student1, Student2)
    }
    /**
     * 实现方法委托
     * @param classes 可变长度的 Class 对象
     */
    def delegate(Class... classes) {
        def objects = classes.collect{
            // 通过反射创建要委托的对象
            it.newInstance()
        }
        // 注入方法需要获取 org.codehaus.groovy.runtime.HandleMetaClass 对象进行注入
        StudentManager sm = this
        sm.metaClass.methodMissing = {
            String name, def args ->
                // 在 objects 数组中查找哪个对象中包含 name(args) 方法
                // 返回该对象赋值给 object 对象
                def object = objects.find{
                    it.respondsTo(name, args)
                }
                if (object) {
                    // 注入 name 方法
                    sm.metaClass."$name" = {
                        object.invokeMethod(name, it)
                    }
                    // 调用刚注入的方法
                    invokeMethod(name, args)
                }
        }
    }
}


二、完整代码示例


完整代码示例 :

class Student1{
    def hello1(){
        println "hello1"
    }
}
class Student2{
    def hello2(){
        println "hello2"
    }
}
class StudentManager{
    {
        // 代码块中调用 delegate 方法 , 传入要委托的类
        delegate(Student1, Student2)
    }
    /**
     * 实现方法委托
     * @param classes 可变长度的 Class 对象
     */
    def delegate(Class... classes) {
        def objects = classes.collect{
            // 通过反射创建要委托的对象
            it.newInstance()
        }
        // 注入方法需要获取 org.codehaus.groovy.runtime.HandleMetaClass 对象进行注入
        StudentManager sm = this
        sm.metaClass.methodMissing = {
            String name, def args ->
                // 在 objects 数组中查找哪个对象中包含 name(args) 方法
                // 返回该对象赋值给 object 对象
                def object = objects.find{
                    it.respondsTo(name, args)
                }
                if (object) {
                    // 注入 name 方法
                    sm.metaClass."$name" = {
                        object.invokeMethod(name, it)
                    }
                    // 调用刚注入的方法
                    invokeMethod(name, args)
                }
        }
    }
}
def sm = new StudentManager()
// 方法委托, 直接通过 StudentManager 对象调用 Student1 中的方法
sm.hello1()
// 方法委托, 直接通过 StudentManager 对象调用 Student2 中的方法
sm.hello2()
/*
    方法委托 : 如果调用的某个对象方法没有定义该对象 , 则可以将该方法委托给内部对象执行
 */

执行结果 :

hello1
hello2

image.png

目录
相关文章
|
数据采集 自然语言处理 搜索推荐
ModelScope问题之模型encoder配置报错如何解决
ModelScope模型报错是指在使用ModelScope平台进行模型训练或部署时遇到的错误和问题;本合集将收集ModelScope模型报错的常见情况和排查方法,帮助用户快速定位问题并采取有效措施。
710 0
|
前端开发 JavaScript
去除router-link中的下划线
这篇文章介绍了如何在Vue.js中去除`<router-link>`元素的默认下划线样式,通过全局CSS覆盖来保持页面样式的整洁。
去除router-link中的下划线
|
安全 搜索推荐 测试技术
【实测】用chatGPT来完整的走一次测试流程吧,看看它到底相当于我们什么等级的工程师?
【实测】用chatGPT来完整的走一次测试流程吧,看看它到底相当于我们什么等级的工程师?
|
Dart API C语言
Dart ffi 使用问题之想在C/C++中创建异步线程来调用Dart方法,如何操作
Dart ffi 使用问题之想在C/C++中创建异步线程来调用Dart方法,如何操作
【Qt 学习笔记】Qt窗口 | 标准对话框 | 输入对话框QInputDialog
【Qt 学习笔记】Qt窗口 | 标准对话框 | 输入对话框QInputDialog
934 3
pid控制器的工作原理
【2月更文挑战第1天】假设你是一个工厂的工程师,你的工作是控制一个生产过程,这个过程是将材料加热到一定的温度,然后通过一个机器将材料加工成成品。
330 9
|
新零售 算法 搜索推荐
理解图表示学习中的负采样 | KDD论文解读
本文“Understanding Negative Sampling in Graph Representation Learning”已被KDD 2020录用。
理解图表示学习中的负采样 | KDD论文解读
|
前端开发 Java 数据库
springboot项目中信息分页查询的常规操作流程
springboot项目中信息分页查询的常规操作流程
257 0
|
安全 Java 数据安全/隐私保护
【Spring底层原理高级进阶】【SpringCloud整合Spring Security OAuth2】深入了解 Spring Security OAuth2:底层解析+使用方法+实战
【Spring底层原理高级进阶】【SpringCloud整合Spring Security OAuth2】深入了解 Spring Security OAuth2:底层解析+使用方法+实战
|
C++
[项目配置] 配置Qt函数库和ui界面库的封装并调用的项目(二)
[项目配置] 配置Qt函数库和ui界面库的封装并调用的项目
222 0