Groovy - 元对象编程

  • 简述

    元对象编程或 MOP 可用于动态调用方法,也可动态创建类和方法。
    那么这是什么意思?让我们考虑一个名为 Student 的类,它是一种没有成员变量或方法的空类。假设您必须在此类上调用以下语句。
    
    Def myStudent = new Student() 
    myStudent.Name = ”Joe”; 
    myStudent.Display()
    
    现在在元对象编程中,即使类没有成员变量Name,也没有方法Display(),上面的代码仍然可以工作。
    这怎么行?好吧,为了解决这个问题,必须实现 GroovyInterceptable 接口以挂钩到 Groovy 的执行过程中。以下是此接口可用的方法。
    
    Public interface GroovyInterceptable { 
       Public object invokeMethod(String methodName, Object args) 
       Public object getproperty(String propertyName) 
       Public object setProperty(String propertyName, Object newValue) 
       Public MetaClass getMetaClass() 
       Public void setMetaClass(MetaClass metaClass) 
    }
    
    所以在上面的接口描述中,假设如果你必须实现 invokeMethod(),它将为存在或不存在的每个方法调用。
  • 缺少属性

    因此,让我们看一个示例,说明如何为缺少的属性实现元对象编程。以下关键的事情应该注意以下代码。
    • Student 类没有定义名为 Name 或 ID 的成员变量。
    • Student 类实现了 GroovyInterceptable 接口。
    • 有一个名为 dynamicProps 的参数,用于保存动态创建的成员变量的值。
    • 已实现方法 getproperty 和 setproperty 以在运行时获取和设置类属性的值。
    
    class Example {
       static void main(String[] args) {
          Student mst = new Student();
          mst.Name = "Joe";
          mst.ID = 1;
          
          println(mst.Name);
          println(mst.ID);
       }
    }
    class Student implements GroovyInterceptable { 
       protected dynamicProps=[:]
       
       void setProperty(String pName,val) {
          dynamicProps[pName] = val
       }
       
       def getProperty(String pName) {
          dynamicProps[pName]
       } 
    } 
    
    以下代码的输出将是 -
    
    Joe 
    1
    
  • 缺少方法

    因此,让我们看一个示例,说明如何为缺少的属性实现元对象编程。以下代码应注意以下关键事项 -
    • Student 类现在实现了 invokeMethod 方法,无论该方法是否存在都会被调用。
    
    class Example {
       static void main(String[] args) {
          Student mst = new Student();
          mst.Name = "Joe";
          mst.ID = 1;
          
          println(mst.Name);
          println(mst.ID);
          mst.AddMarks();
       } 
    }
     
    class Student implements GroovyInterceptable {
       protected dynamicProps = [:]  
        
       void setProperty(String pName, val) {
          dynamicProps[pName] = val
       } 
       
       def getProperty(String pName) {
          dynamicProps[pName]
       }
       
       def invokeMethod(String name, Object args) {
          return "called invokeMethod $name $args"
       }
    }
    
    以下代码的输出如下所示。请注意,即使 Display 方法不存在,也不会出现缺少 Method Exception 的错误。
    
    Joe 
    1 
    
  • 元类

    此功能与 MetaClass 实现相关。在默认实现中,您可以访问字段而无需调用它们的 getter 和 setter。下面的示例显示了如何使用 metaClass 函数我们能够更改类中私有变量的值。
    
    class Example {
       static void main(String[] args) {
          Student mst = new Student();
          println mst.getName()
          mst.metaClass.setAttribute(mst, 'name', 'Mark')
          println mst.getName()
       } 
    } 
    class Student {
       private String name = "Joe";
       
       public String getName() {
          return this.name;
       } 
    }
    
    以下代码的输出将是 -
    
    Joe 
    Mark
    
  • 缺少方法

    Groovy 支持 methodMissing 的概念。此方法与 invokeMethod 的不同之处在于它仅在方法分派失败的情况下调用,此时找不到给定名称和/或给定参数的方法。以下示例显示了如何使用 methodMissing。
    
    class Example {
       static void main(String[] args) {
          Student mst = new Student();
          mst.Name = "Joe";
          mst.ID = 1;
          
          println(mst.Name);
          println(mst.ID);
          mst.AddMarks();
       } 
    } 
    class Student implements GroovyInterceptable {
       protected dynamicProps = [:]  
        
       void setProperty(String pName, val) {
          dynamicProps[pName] = val
       }
       
       def getProperty(String pName) {
          dynamicProps[pName]
       }
       
       def methodMissing(String name, def args) {         
          println "Missing method"
       }  
    }
    
    以下代码的输出将是 -
    
    Joe 
    1 
    Missing method