第八章 Groovy 动态编程
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、总结
- 对象协议(MOP)
- metaclass 使用
第八章 Groovy 动态编程相关推荐
- java学习笔记-第八章:面向对象编程(中级部分)
第八章:面向对象编程(中级部分) 总体内容 IDEA IDEA介绍 ECLIPSE介绍 IDEA使用 破解IDEA2020.2.2 IDEA工作界面介绍 IDEA调整代码,导航栏的字体大小,主题颜色, ...
- Java动态编程技术
Java是一种静态显式强类型语言,导致java代码存在大量的模版化代码,一直被人诟病开发效率低.其实java语言本身以及JVM生态提供了大量动态编程技术,可以大量减少模版化代码.本文尝试整理相关的技术 ...
- Java动态编程初探
作者简介 传恒,一个喜欢摄影和旅游的软件工程师,先后从事饿了么物流蜂鸟自配送和蜂鸟众包的开发,现在转战 Java,目前负责物流策略组分流相关业务的开发. 什么是动态编程 动态编程是相对于静态编程而言的 ...
- [.NET] 《Effective C#》快速笔记 - C# 中的动态编程
<Effective C#>快速笔记 - C# 中的动态编程 静态类型和动态类型各有所长,静态类型能够让编译器帮你找出更多的错误,因为编译器能够在编译时进行大部分的检查工作.C# 是一种静 ...
- 【Groovy】Groovy 动态语言特性 ( Groovy 中的变量自动类型推断以及动态调用 | Java 中必须为变量指定其类型 )
文章目录 前言 一.Groovy 动态语言 二.Groovy 中的变量自动类型推断及动态调用 三.Java 中必须为变量指定其类型 前言 Groovy 是动态语言 , Java 是静态语言 ; 一.G ...
- Java动态编程初探——Javassist
最近需要通过配置生成代码,减少重复编码和维护成本.用到了一些动态的特性,和大家分享下心得. 我们常用到的动态特性主要是反射,在运行时查找对象属性.方法,修改作用域,通过方法名称调用方法等.在线的应用不 ...
- JavaScript实现唯一路径问题的动态编程方法的算法(附完整源码)
JavaScript实现唯一路径问题的动态编程方法的算法(附完整源码) dpUniquePaths.js完整源代码 dpUniquePaths.test.js完整源代码 dpUniquePaths.j ...
- JavaScript实现截留雨水问题的动态编程方法算法(附完整源码)
JavaScript实现截留雨水问题的动态编程方法算法(附完整源码) dpRainTerraces.js完整源代码 dpRainTerraces.tset.js完整源代码 dpRainTerraces ...
- JavaScript实现跳跃游戏的动态编程自上而下的方法算法(附完整源码)
JavaScript实现跳跃游戏的动态编程自上而下的方法算法(附完整源码) dpTopDownJumpGame.js完整源代码 dpTopDownJumpGame.test.js完整源代码 dpTop ...
最新文章
- MQCache 秒开缓存快速入门指南 - 旁路(使用镜像交换机)
- java中字符串压缩成bcd码_Java 压缩 / 解压缩字符串
- Windows 系统常见操作
- MenuItem创建注意事项
- 201612-5 卡牌游戏
- 深度学习基本概念笔记
- 广元南山隧道南河互通立交图_广元城区一隧道工程竣工时间已定,今后出行更加方便了!...
- 【操作系统】进程与线程
- mysql数据库查询的传统句子
- bottleneck resnet网络_Detection学习之四-利用pytorch实现resnet
- 的有效 海思编码_【最佳案例展示】2020年CUVA“超高清视频创新产品与解决方案”全球首款8K@120解码芯片海思Hi3796CV300...
- 语音识别之DTW算法的应用(Python)
- linux jdk下载并安装
- Rust 限流算法crate调研
- 阿里云域名注册+服务器购买+备案教程
- LeetCode知识点总结 - 884
- 读计算机必看:美国顶尖IT公司从哪些大学招人最多?
- Mycat 读写分离+分库分表
- Android-Rxjava 常用操作符
- UNETR 论文精解
热门文章
- 评论/点赞/分享/收藏/上传/下载/收索/ 测试点
- 几个欧洲人是如何于百万军中取印加国王手机的?
- 一键转换手写为文字,有什么软件可以识别手写字
- 红粉NBA:那些在联盟中的跨国恋情
- 鸿蒙合香丸的副作用,苏合香丸功能主治是什么 有副作用吗
- nuxt.js 跳转新页面
- android设备和oppo一样,买手机选OPPO还是华为?中端机对决,答案果不其然
- selenium webdriver 页面刷新
- Windows10 使命召唤14二战:由于找不到MSVCR120.dll ……
- 感恩节 | 致通信人,那个不为人知的自己