ad_qqread_mid_big">
通过动态代理类来创建一个通用的缓存包装器
上面第二种方法仅有的缺点就是缓存包装器不能重用,每次我们希望添加一个缓存给某个类,我们就要写一个特殊的缓存包装器给目标接口.这是一个很慢,容易出错的过程.
jdk1.3开始支持动态代理类: 特别的类能够在运行期决定实现哪个接口-通常的模式都是,在运行期即决定实现哪个接口.通过这个,我们有可能实现一个通用的缓存包装器,我们称它为memoizer,在运行期决定实现哪个接口.这样, cachingbinarydigitscalculator就是不再需要的.它是这样被调用的:
可以通过memoizer来重写如下:
当调用静态方法memoize的时候,将会创建一个新的代理实例-也就是一个java.lang.reflect.proxy的实例.实现了一个接口集.这个接口集由object.getclass().getinterfaces()来决定.每个代理实例包含一个java.lang.reflect.invocationhandler实例来处理这个代理实例调用的相关方法.在我们的例子里,memoizer就是一个invocationhandler实例.
当一个方法在代理实例里被调用,比如, calculatebinarydigit,那么, memoizer实例里的invoke方法就会被调用,相关信息会传给invoke方法,以决定proxy实例调用了哪个方法,包含参数信息.在我们的例子里,传入memoizer的java.lang.method参数是calculatebinarydigit,而参数信息则是pi需要精确的位数-整数n.在这个基础上,memoizer能够进一步进行缓存操作的.
在例子里(caches是一个hashmap,cache是一个map)里用到的key,主要是传入的方法信息:method对象和参数对象. 为了实现的简单与通用性,memoizer有一个关于cache的hashmap caches,每个method是一个key,对应的value为一个cache.然后把参数信息转化成一个list对象,作为cache的key.使用list是很方便的,同时也可以保证equals()方法,所以能够保证当且仅当参数信息完全相同的时候这个list才相等.
一旦一个cache的key被创建,那么,计算之前都会先查找这个cache,如果找到,则返回cache里的值.否则,如果带有这些参数的这个方法没有被调用过,那么,则会通过invoke来调用这个method.在我们的例子里, 实例pibinarydigitscalculator 里的calculatebinarydigit方法将会通过invoke被调用.而且计算结果将会被存在cache里. >>>更多专题请看java的类专题
通过动态代理类来创建一个通用的缓存包装器
上面第二种方法仅有的缺点就是缓存包装器不能重用,每次我们希望添加一个缓存给某个类,我们就要写一个特殊的缓存包装器给目标接口.这是一个很慢,容易出错的过程.
jdk1.3开始支持动态代理类: 特别的类能够在运行期决定实现哪个接口-通常的模式都是,在运行期即决定实现哪个接口.通过这个,我们有可能实现一个通用的缓存包装器,我们称它为memoizer,在运行期决定实现哪个接口.这样, cachingbinarydigitscalculator就是不再需要的.它是这样被调用的:
| binarydigitscalculator calculator = new cachingbinarydigitscalculator( new pibinarydigitscalculator() ); |
可以通过memoizer来重写如下:
| binarydigitscalculator calculator = (binarydigitscalculator) memoizer.memoize( new pibinarydigitscalculator() ); memoizer的代码如下: import java.lang.reflect.invocationhandler; import java.lang.reflect.invocationtargetexception; import java.lang.reflect.method; import java.lang.reflect.proxy; import java.util.arrays; import java.util.collections; import java.util.hashmap; import java.util.list; import java.util.map; public class memoizer implements invocationhandler { public static object memoize(object object) { return proxy.newproxyinstance( object.getclass().getclassloader(), object.getclass().getinterfaces(), new memoizer(object) ); } private object object; private map caches = new hashmap(); private memoizer(object object) { this.object = object; } public object invoke(object proxy, method method, object[] args) throws throwable { if (method.getreturntype().equals(void.type)) { // don't cache void methods return invoke(method, args); } else { map cache = getcache(method); list key = arrays.aslist(args); object value = cache.get(key); if (value == null && !cache.containskey(key)) { value = invoke(method, args); cache.put(key, value); } return value; } } private object invoke(method method, object[] args) throws throwable { try { return method.invoke(object, args); } catch (invocationtargetexception e) { throw e.gettargetexception(); } } private synchronized map getcache(method m) { map cache = (map) caches.get(m); if (cache == null) { cache = collections.synchronizedmap( new hashmap() ); caches.put(m, cache); } return cache; } } |
当调用静态方法memoize的时候,将会创建一个新的代理实例-也就是一个java.lang.reflect.proxy的实例.实现了一个接口集.这个接口集由object.getclass().getinterfaces()来决定.每个代理实例包含一个java.lang.reflect.invocationhandler实例来处理这个代理实例调用的相关方法.在我们的例子里,memoizer就是一个invocationhandler实例.
当一个方法在代理实例里被调用,比如, calculatebinarydigit,那么, memoizer实例里的invoke方法就会被调用,相关信息会传给invoke方法,以决定proxy实例调用了哪个方法,包含参数信息.在我们的例子里,传入memoizer的java.lang.method参数是calculatebinarydigit,而参数信息则是pi需要精确的位数-整数n.在这个基础上,memoizer能够进一步进行缓存操作的.
在例子里(caches是一个hashmap,cache是一个map)里用到的key,主要是传入的方法信息:method对象和参数对象. 为了实现的简单与通用性,memoizer有一个关于cache的hashmap caches,每个method是一个key,对应的value为一个cache.然后把参数信息转化成一个list对象,作为cache的key.使用list是很方便的,同时也可以保证equals()方法,所以能够保证当且仅当参数信息完全相同的时候这个list才相等.
一旦一个cache的key被创建,那么,计算之前都会先查找这个cache,如果找到,则返回cache里的值.否则,如果带有这些参数的这个方法没有被调用过,那么,则会通过invoke来调用这个method.在我们的例子里, 实例pibinarydigitscalculator 里的calculatebinarydigit方法将会通过invoke被调用.而且计算结果将会被存在cache里.
| 上一页 1 2 3 4 下一页 |
| 相关内容:设计 包装 python perl java |
| 【收藏此页】【大 中 小】【打印】【关闭】 | |
| 上一篇:java设计模式之工厂方法模式 下一篇:基于eclipse开发轻量级spring插件 10万个软件免费高速下载 | |
| ||||||||||||||
|
|
-
关于我们
公司介绍 最新动态 联系我们 -
产品与服务
域名注册 jsp空间 php空间 -
常见问题
空间操作手册 网站备案相关 退款相关问题 -
技术支持
技术 QQ :178966803 联系电话:13616026886 联系邮箱:fjjsp@vip.163.com
扫描关注微信公众号
闽公网安备 35060202000074号