1、什么是动态编程

  • 经典编程,类一经编译,后面不能修改了

2、元对象协议(MOP)

  • 委托动态行为是通过hook 方法

3、利用(hook)钩子方法自定义MOP

3.1、自定义methodMissing(当方法不存在默认调用的方法

  • /*** 自定义方法不存在的时候调用* @author liangchen* @date 2020/11/10*/
    class CustomizingMethodMissing {def methodMissing(String name, Object args) {"called $name with $args"}static void main(String[] args) {def customer = new CustomizingMethodMissing()// 方法不存在,自动调用methodMissing 方法, 设计哲学是避免MissingMethodException 异常assert customer.hello('world') == 'called hello with [world]'def people = new MiniGorm()def dierk = [first:'Dierk', last:'Koenig']def paul = [first:'Paul', last: 'King']people.db << dierk << paulassert  people.findByFirst('Dierk') == dierkassert people.findByLast('King') == paul}static class MiniGorm{def db = []def methodMissing(String name, Object args) {db.find {it [name.toLowerCase()-'findby'] == args[0]}}}
    }

3.2、自定义propertyMissing(当成员变量不存在)

  • 属性不存在自动调用

  • /*** 属性 不存在* @author liangchen* @date 2020/11/10*/
    class CustomizingPropertyMissing {def propertyMissing(String name) {"accessed $name"}static void main(String[] args) {def bounce = new CustomizingPropertyMissing()assert bounce.hello == 'accessed hello'def dslMissing = new DSLMissingProperty();assert dslMissing.IIOI + dslMissing.IOI == dslMissing.IOOIO}
    }
    class DSLMissingProperty{def propertyMissing(String name) {int result = 0name.each {// 移位运算result <<=1if(it == 'I') result++}return result}
    }
    

3.3、为动态钩子使用闭包

  • /*** 重写Closure来动态方法* @author liangchen* @date 2020/11/10*/
    class ClosureProperty {Closure whatToDo = {name -> "accessed $name"}def propertyMissing(String name) {whatToDo(name)}static void main(String[] args) {def one = new ClosureProperty()assert one.hello == 'accessed hello'//重写闭包实现动态方法特性one.whatToDo = {name -> name.size()}assert one.hello == 5}
    }

3.4、自定义Groovy 对象的方法

  • 实现GroovyObject 接口

  • GroovyObjectSupport 实现 GroovyObject接口,同时提供默认实现

    • package com.jack.groovy.ch8/*** 无参的方法调用* @author liangchen* @date 2020/11/11*/
      class GetProperty86 {def getProperty(String propertyName) {if (metaClass.hasProperty(this, propertyName)) {return metaClass.getProperty(this, propertyName)}// 调用空参数的构造方法invokeMethod propertyName,null}static void main(String[] args) {def user = new PropUser()assert  user.existingProperty// user.toString   invokeMethod  toString nullassert  user.toString() == user.toString}
      }class PropUser extends GetProperty86 {boolean  existingProperty = true
      }
      

4、通过metaclass( 元类)修改类行为

4.1、MetaClass 全方位了解

  • /*** metaClass 理解* @author liangchen* @date 2020/11/11*/
    class MetaClass87 {static void main(String[] args) {MetaClass mc= String.metaClassfinal Object[] NO_ARGS = []// 返回值数量assert  1 == mc.respondsTo("toString", NO_ARGS).size()// 属性assert 3 == mc.properties.size()// 方法个数assert 76 == mc.methods.size()// meta方法assert 215 == mc.metaMethods.size()// 调用toString方法assert "" == mc.invokeMethod("", "toString", NO_ARGS)//调用静态方法assert null == mc.invokeStaticMethod(String, "println", NO_ARGS)//调用构造方法assert "111111" == mc.invokeConstructor("111111")}
    }

4.2、如何找到metaClass, 然后调用其方法

  • 利用自动拦截器类实现metaclass替换

    • /*** 生成代理类替换原有的metaClass,实现拦截器功能* @author liangchen* @date 2020/11/11*/
      class ProxyMetaClass88 {static void main(String[] args) {//创建一个拦截器def tracer = new TracingInterceptor(writer: new StringWriter())// 生成代理原数据def proxyMetaClass = ProxyMetaClass.getInstance(InspectMe)// 代理类设置拦截器proxyMetaClass.interceptor = tracerInspectMe inspectMe = new InspectMe()// 手动定义aop切面proxyMetaClass.use(inspectMe){println "代理类开始"inspectMe.outer()println "代理类结束"}// 将inspectMe类的metaClass替换inspectMe.metaClass = proxyMetaClassassert  1 == inspectMe.outer()println tracer.writer.toString()assert  tracer.writer.toString() =="""before com.jack.groovy.ch8.InspectMe.outer()before com.jack.groovy.ch8.InspectMe.inner()after  com.jack.groovy.ch8.InspectMe.inner()after  com.jack.groovy.ch8.InspectMe.outer()"""}}
      class InspectMe{int outer(){return  inner()}private int inner(){return 1}
      }

4.3、设置其他的metaClass

4.4、扩展 metaclass

  • 使用Expando 和 ExpandoMetaClass

  • /*** Expando 相当于一个盒子,你可以自定义你类和方法* @author liangchen* @date 2020/11/11*/
    class Expando89 {static void main(String[] args) {def boxer = new Expando()// 定义一个方法takThis 返回值good!boxer.takeThis = 'good!'//定义闭包 调用三次takeThis方法,字符串拼接boxer.fightBack = { times -> takeThis * times }assert boxer.fightBack(3) == 'good!good!good!'//def addLow= new AddLowMethodToString810()addLow.addLowMethod()}
    }
    /** 利用 ExpandoMetaClass * 新增low方法 toLowerCase*/
    class AddLowMethodToString810{void addLowMethod(){assert  String.metaClass =~ /MetaClassImpl/// 新增low 调用toLowerCase -> 前面没有值表示无参String.metaClass.low = {-> delegate.toLowerCase()}assert String.metaClass =~ /ExpandoMetaClass/assert "DiErK".low() == 'dierk'}
    }
  • 使用类和对象扩展属性

  • /*** 在类和对象上添加方法和属性* @author liangchen* @date 2020/11/11*/
    class MyGroovy1 {static void main(String[] args) {def before = new MyGroovy1()//类添加方法MyGroovy1.metaClass.myProp = "MyGroovy prop"MyGroovy1.metaClass.test = { -> myProp}try{// 设置在创建对象之前before.test()assert false, "should throw MME"}catch(mme){}// 后面创建对象就可以了assert  new MyGroovy1().test() == 'MyGroovy prop'//def myGroovy =  new MyGroovy2()myGroovy.myCustomizeString()}
    }
    class MyGroovy2{/*** 对象添加方法*/void myCustomizeString(){def myGroovy = new String()myGroovy.metaClass.myProp = "MyJava prop"myGroovy.metaClass.test = { -> myProp }try {new String().test()assert false, 'should throw MME'} catch (mme) {println "error"}assert myGroovy.test() == "MyJava prop"}
    }
  • 变更String类的metaClass 实例

  • /*** 奥赛德编码和解码, 自定义String 类的MetaClass  添加字符* @author liangchen* @date 2020/11/11*/
    class DecodingOdyssey814 {/*** 字符转成ASCII 码+shift, 然后转成字符* @param string 原字符串* @param distance 每个字符+shift 组成字符串* @return*/def move(string, distance) {string.collect { (it as char) + distance as char}.join()}static void main(String[] args) {def decoding =  new DecodingOdyssey814()// 自定义String 类的metaClassString.metaClass{shift = -1// delegate 本对象 this ( "IBM")encode {-> decoding.move delegate, shift}decode {-> decoding.move delegate, -shift}getCode{-> encode()}getOrig{-> decode()}}assert "IBM".encode()=="HAL"assert "HAL".orig == "IBM"def ibm = "IBM"ibm.shift = 7assert  ibm.code == 'PIT'}}
  • 添加静态的方法和父类定义的方法,子类可以共享

    • /*** 添加静态方法 和父类添加的方法子类都可以共享* @author liangchen* @date 2020/11/11*/
      class AddStatic {static void main(String[] args) {// 添加静态方法Integer.metaClass.static.answer = {-> 42}assert Integer.answer() == 42//父类添加的方法,子类都是可以共享的MySuperGroovy.metaClass.added = {-> true}//子类共享assert new MySubGroovy().added()Map.metaClass.toTable = {// 变更展示的方式-> delegate.collect{[it.key, it.value]}}assert [a:1,b:2].toTable() == [["a",1],["b",2]]}}
      /*** 父类添加的方法,子类都是可以共享的*/class MySuperGroovy{}class MySubGroovy extends  MySuperGroovy{}
  • 自定义String的methodMissing方法

    • /*** 自定义String的methodMissing 方法, 新增方法* @author liangchen* @date 2020/11/11*/
      class MopHook817 {static void main(String[] args) {String.metaClass{// 加上前缀,在原字符上rightShiftUnsigned = {// 所有匹配字符前面都会加上前缀 \w 单词prefix -> delegate.replaceAll(~/\w+/) {prefix + it}}// 当方法不存在就会调用这个方法, name是方法名methodMissing = {String name, params ->delegate.replaceAll name, params[0]}}def people = "Dierk,Guillaume,Paul,Hamlet,Jon"//people = people.rightShiftUnsigned("prefix").Dierk('Mittie').Guillaume("Mr.G")println people}
      }

4.5、使用category 类临时修改MOP

  • 重写unMarshal和marshal方法

  • /*** marshal 和 unMarshal 方法转换* @author liangchen* @date 2020/11/11*/
    class MarShal {/*** 转换方法* @param self* @return*/static String marshal(Integer self) {self.toString()}/*** 转换* @param self* @return*/static Integer unMarshal(String self) {self.toInteger()}static void main(String[] args) {use MarShal, {assert 1.marshal() == "1"//等于assert marshal(1) == "1"assert "1".unMarshal() == 1unMarshal("1") == 1[Integer.MIN_VALUE, -1, 0, Integer.MAX_VALUE].each {assert it.marshal().unMarshal() == it}}}
    }

4.6、写扩展模块

  • 暂时没有看明白

4.7、使用@Category 注解

  • /*** 利用@Category 添加marshal 和unMarshal* @author liangchen* @date 2020/11/11*/
    class AnotationCategory {static void main(String[] args) {use([IntegerMarshal, StringMarshal]) {assert 1.marshal() == '1'assert "1".unMarshal() ==1}}
    }
    @Category(Integer)
    class IntegerMarshal{String marshal(){toString()}}
    @Category(String)class StringMarshal{Integer unMarshal(){this.toInteger()}
    }
    

4.8、使用Mixins合并类

  • 使得某个类方法在其他类中可以直接使用

  • /*** 合并方法* @author liangchen* @date 2020/11/11*/
    class Mixin821 {}//这个相当于继承了MessageFeature,具有它的方法
    @Mixin(MessageFeature)
    class FirstTest extends GroovyTestCase{void testWithMixinUsage(){message = "Called from Test"assertMessage "Called from Test"}
    }class MessageFeature{def messagevoid assertMessage(String msg) {assertEquals msg, message}
    }
    
  • ArrayList的mixin方法

    • import groovy.test.GroovyTestCase/*** ArrayList的mixin的方法* @author liangchen* @date 2020/11/11*/class Even822 extends GroovyTestCase{void testArrayListMixin() {//合并多个方法,这样读起来很简洁ArrayList.mixin EvenSieve, MinusSieve,PlusSieve//这里-, + 分别执行MinusSieve的minus 和PlusSieve.plusassert (0..10).toList().no2-3+7==[1,5]}
      }
      class EvenSieve {def getNo2(){removeAll { it % 2 == 0 }return this}}
      /*** 执行减法时候,说明groovy 内置minus方法*/
      class MinusSieve{def minus(int num) {removeAll { it % num == 0 }return this}
      }/*** 执行加法时候调用这个方法 说明groovy 内置plus方法*/
      class PlusSieve{def plus(int num) {removeAll { it % num == 0 }return this}
      }

5、真实的动态编程

5.1、计算指标

  • /*** 比如计算不同规则,例如不同币种计算总资产* @author liangchen* @date 2020/11/11*/
    class MetricCalculation823 extends GroovyTestCase{void testMetricCalculations(){//先添加两个方法,10.mm会调用getMm方法Number.metaClass{getMm = { delegate }getCm = { delegate * 10.mm }getM = {delegate * 100.cm}}assert 1.m + 20.cm - 8.mm == 1.192.m}}

5.2、利用工厂方法替换构造方法创建对象

  • import groovy.test.GroovyTestCaseimport java.awt.Dimension/*** @author liangchen* @date 2020/11/11*/
    class FactoryReplace824  extends GroovyTestCase{void testDefiniteStaticFactoryForAllClass(){//为所有Class添加一个make方法Class.metaClass.make = { Object[] args ->delegate.metaClass.invokeConstructor(*args)}assert new HashMap<>() == HashMap.make()assert new Integer(42) == Integer.make(42)assert new Dimension(2,3) == Dimension.make(2,3)}
    }

5.3、傻瓜式的IDE工具

  • 没有看懂

  • import groovy.test.GroovyTestCase/*** @author liangchen* @date 2020/11/11*/
    class Temporarily825 extends GroovyTestCase {static connections = []static setInChannel(ChannelComponent self, value) {connections << [target: self, source: value]}static getOutChannel(ChannelComponent self) {self}void testChannelComponent(){def producer =new Producer()def adaptor = new Adaptor()def printer = new Printer()// 使用这个class,调用setInChannel然后给connections赋值use Temporarily825, {adaptor.inChannel = producer.outChannelprinter.inChannel = adaptor.outChannel}assert Temporarily825.connections == [[source: producer, target: adaptor],[source: adaptor, target: printer]]}
    }
    interface ChannelComponent{}class Producer implements ChannelComponent{List<Integer> outChannel
    }class Adaptor implements ChannelComponent{List<Integer> inChannelList<String> outChannel
    }class Printer implements ChannelComponent{List<String> inChannel
    }

5.4、撤回 me他class修改

  • /*** 撤销方法* @author liangchen* @date 2020/11/12*/
    class Undo826 {static void main(String[] args) {//原来的class元数据MetaClass oldMetaClass = String.metaClassMetaMethod alias = String.metaClass.metaMethods.find { it.name == 'size' }String.metaClass{// 调用size()方法oldSize = { -> alias.invoke delegate }size = { -> oldSize() * 2 }}//调用新增的方法assert "abc".size() == 6assert "abc".oldSize() == 3if (oldMetaClass.is(String.metaClass)) { //falseString.metaClass {size = { -> alias.invoke delegate }oldSize = { -> throw new UnsupportedOperationException() }}} else {// 恢复原来String的MetaClassString.metaClass = oldMetaClass}assert "abc".size() == 3}}

5.5、拦截器、缓存、调用模式

  • /*** 自导自演* @author liangchen* @date 2020/11/12*/
    class Intercept827 extends GroovyTestCase{void  testInterceptCacheInvokePattern(){ArrayList.metaClass.methodMissing= {String name, Object args ->assert name.startsWith("findBy")assert args.size() ==1// 定义一个方法Object.metaClass."$name" = {value ->delegate.find{ it[name.toLowerCase()-'findby'] == value}}// 直接调用刚刚定义的方法delegate."$name"(args[0])}def data = [[name:'moon', au:0.0025],[name:'sun',au:1],[name:'nepture', au: 30]]assert data.findByName('moon')assert data.findByName('sun')assert data.findByAu(1)assert data.find{it['name']=='moon'}}}

6、总结

  1. 对象协议(MOP)
  2. metaclass 使用

第八章 Groovy 动态编程相关推荐

  1. java学习笔记-第八章:面向对象编程(中级部分)

    第八章:面向对象编程(中级部分) 总体内容 IDEA IDEA介绍 ECLIPSE介绍 IDEA使用 破解IDEA2020.2.2 IDEA工作界面介绍 IDEA调整代码,导航栏的字体大小,主题颜色, ...

  2. Java动态编程技术

    Java是一种静态显式强类型语言,导致java代码存在大量的模版化代码,一直被人诟病开发效率低.其实java语言本身以及JVM生态提供了大量动态编程技术,可以大量减少模版化代码.本文尝试整理相关的技术 ...

  3. Java动态编程初探

    作者简介 传恒,一个喜欢摄影和旅游的软件工程师,先后从事饿了么物流蜂鸟自配送和蜂鸟众包的开发,现在转战 Java,目前负责物流策略组分流相关业务的开发. 什么是动态编程 动态编程是相对于静态编程而言的 ...

  4. [.NET] 《Effective C#》快速笔记 - C# 中的动态编程

    <Effective C#>快速笔记 - C# 中的动态编程 静态类型和动态类型各有所长,静态类型能够让编译器帮你找出更多的错误,因为编译器能够在编译时进行大部分的检查工作.C# 是一种静 ...

  5. 【Groovy】Groovy 动态语言特性 ( Groovy 中的变量自动类型推断以及动态调用 | Java 中必须为变量指定其类型 )

    文章目录 前言 一.Groovy 动态语言 二.Groovy 中的变量自动类型推断及动态调用 三.Java 中必须为变量指定其类型 前言 Groovy 是动态语言 , Java 是静态语言 ; 一.G ...

  6. Java动态编程初探——Javassist

    最近需要通过配置生成代码,减少重复编码和维护成本.用到了一些动态的特性,和大家分享下心得. 我们常用到的动态特性主要是反射,在运行时查找对象属性.方法,修改作用域,通过方法名称调用方法等.在线的应用不 ...

  7. JavaScript实现唯一路径问题的动态编程方法的算法(附完整源码)

    JavaScript实现唯一路径问题的动态编程方法的算法(附完整源码) dpUniquePaths.js完整源代码 dpUniquePaths.test.js完整源代码 dpUniquePaths.j ...

  8. JavaScript实现截留雨水问题的动态编程方法算法(附完整源码)

    JavaScript实现截留雨水问题的动态编程方法算法(附完整源码) dpRainTerraces.js完整源代码 dpRainTerraces.tset.js完整源代码 dpRainTerraces ...

  9. JavaScript实现跳跃游戏的动态编程自上而下的方法算法(附完整源码)

    JavaScript实现跳跃游戏的动态编程自上而下的方法算法(附完整源码) dpTopDownJumpGame.js完整源代码 dpTopDownJumpGame.test.js完整源代码 dpTop ...

最新文章

  1. MQCache 秒开缓存快速入门指南 - 旁路(使用镜像交换机)
  2. java中字符串压缩成bcd码_Java 压缩 / 解压缩字符串
  3. Windows 系统常见操作
  4. MenuItem创建注意事项
  5. 201612-5 卡牌游戏
  6. 深度学习基本概念笔记
  7. 广元南山隧道南河互通立交图_广元城区一隧道工程竣工时间已定,今后出行更加方便了!...
  8. 【操作系统】进程与线程
  9. mysql数据库查询的传统句子
  10. bottleneck resnet网络_Detection学习之四-利用pytorch实现resnet
  11. 的有效 海思编码_【最佳案例展示】2020年CUVA“超高清视频创新产品与解决方案”全球首款8K@120解码芯片海思Hi3796CV300...
  12. 语音识别之DTW算法的应用(Python)
  13. linux jdk下载并安装
  14. Rust 限流算法crate调研
  15. 阿里云域名注册+服务器购买+备案教程
  16. LeetCode知识点总结 - 884
  17. 读计算机必看:美国顶尖IT公司从哪些大学招人最多?
  18. Mycat 读写分离+分库分表
  19. Android-Rxjava 常用操作符
  20. UNETR 论文精解

热门文章

  1. 评论/点赞/分享/收藏/上传/下载/收索/ 测试点
  2. 几个欧洲人是如何于百万军中取印加国王手机的?
  3. 一键转换手写为文字,有什么软件可以识别手写字
  4. 红粉NBA:那些在联盟中的跨国恋情
  5. 鸿蒙合香丸的副作用,苏合香丸功能主治是什么 有副作用吗
  6. nuxt.js 跳转新页面
  7. android设备和oppo一样,买手机选OPPO还是华为?中端机对决,答案果不其然
  8. selenium webdriver 页面刷新
  9. Windows10 使命召唤14二战:由于找不到MSVCR120.dll ……
  10. 感恩节 | 致通信人,那个不为人知的自己