|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
手机用到的是用j2me所编出来的小程序。静态影象是衍生自Lisp,Python,和Perl等历程性言语的一种计划形式,它能够对上次的盘算了局举行影象。一个完成了影象功效的函数,带有显式的cache,以是,已盘算过的了局就可以间接从cache中取得,而不必每次都举行盘算.
影象能明显的提拔年夜盘算量代码的效力.并且是一种可重用的计划.
本文论述了在Java中利用这一形式的办法,并供应了一个能够供应上述功效的"影象类":
Foofoo=(Foo)Memoizer.memoize(newFooImpl());
这里,Foo是一个接口,它含有的办法是必要影象的.FooImpl是Foo的一个完成.foo是Foo的一个援用.办法与FooImpl基础不异,区分在于Foo前往的值,会被缓存起来.单个影象类的长处在于为任何类增加影象功效是很复杂的:界说一个包括必要影象的办法的接口,然后挪用memoize来完成一个实例.
为了了解影象类是怎样完成的,我们将分几步来注释.起首,我注释一下为什么缓存可以在必要它的类中完成.然后,我测试一下怎样为一个特定的类增加缓存包装器.最初,我注释一下怎样才干使得一个缓存包装器可以通用于恣意的类.
为年夜盘算量的程序增加缓存
作为一个年夜盘算量程序的例子,我们思索PiBinaryDigitsCalculator这个例子-盘算二进制数据pi.唯一的public办法calculateBinaryDigit带有一个参数:整数n,代表必要准确到的位数.比方,1000000,将会前往小数点后的一百万位,经由过程byte值前往-每位为0大概1.(算法能够参考:http://www.cecm.sfu.ca/~pborwein/PAPERS/P123.pdf)
publicclassPiBinaryDigitsCalculator{
/**
*Returnsthecoefficientof2^ninthebinary
*expansionofpi.
*@paramnthebinarydigitofpitocalculate.
*@throwsValidityCheckFailedExceptionifthevalidity
*checkfails,thismeanstheimplementationisbuggy
*ornistoolargeforsufficientprecisiontobe
*retained.
*/
publicbytecalculateBinaryDigit(finalintn){
returnrunBBPAlgorithm(n);
}
privatebyterunBBPAlgorithm(finalintn){
//Lengthyroutinegoeshere...
}
}
最复杂间接的办法来缓存前往值能够经由过程修正这个类来完成:增加一个Map来保留之前盘算失掉的值,以下:
importjava.util.HashMap;
publicclassPiBinaryDigitsCalculator{
privateHashMapcache=newHashMap();
publicsynchronizedbytecalculateBinaryDigit(
finalintn){
finalIntegerN=newInteger(n);
ByteB=(Byte)cache.get(N);
if(B==null){
byteb=runBBPAlgorithm(n);
cache.put(N,newByte(b));
returnb;
}else{
returnB.bytevalue();
}
}
privatebyterunBBPAlgorithm(finalintn){
//Lengthyroutinegoeshere...
}
}
calculateBinaryDigit办法起首会反省HashMap内里是不是缓存了这个关头字-参数n,假如找到了,就间接前往这个值.不然,就会举行这个冗杂的盘算,并将了局保留到缓存内里.在增加进HashMap的时分,在原始范例和对象之间还要举行小小的转换.
只管这个办法是可行的,可是有几个弱点.起首,举行缓存的代码和一般的算法代码不是明显分隔的.一个类,不但卖力举行盘算,也要卖力举行保护缓存数据.如许,要举行一些测试就会显得很坚苦.好比,不克不及写一个测试程序来测试这个算法延续地前往不异的值,由于,从第二次入手下手,了局都是间接从cache中取得了.
其次,当缓存代码不再必要,移除它会变得坚苦,由于它和算法块地代码是严密分离在一同的.以是,要想晓得缓存是不是带来了很高的效力提拔也是很坚苦的,由于不克不及写一个测试程序是弛缓存数据分隔的.当你改善了你的算法,缓存有大概生效-可是这个时分你其实不晓得.
第三,缓存代码不克不及被重用.只管代码服从了一个一般的形式,可是都是在一个类-PiBinaryDigitsCalculator内里.
后面两个成绩都能够经由过程机关一个缓存包装器来办理.
缓存包装器
经由过程利用Decorator形式,要分隔盘算代码弛缓存代码是很简单的.起首,界说一个接口,内里界说基础的办法.
publicinterfaceBinaryDigitsCalculator{
publicbytecalculateBinaryDigit(finalintn);
}
然后界说两个完成,分离卖力两个义务:
publicclassPiBinaryDigitsCalculator
implementsBinaryDigitsCalculator{
publicbytecalculateBinaryDigit(finalintn){
returnrunBBPAlgorithm(n);
}
privatebyterunBBPAlgorithm(finalintn){
//Lengthyroutinegoeshere...
}
}
importjava.util.HashMap;
publicclassCachingBinaryDigitsCalculatorimplements
BinaryDigitsCalculator{
privateBinaryDigitsCalculatorbinaryDigitsCalculator;
privateHashMapcache=newHashMap();
publicCachingBinaryDigitsCalculator(
BinaryDigitsCalculatorcalculator){
this.binaryDigitsCalculator=calculator;
}
publicsynchronizedbytecalculateBinaryDigit(intn){
finalIntegerN=newInteger(n);
ByteB=(Byte)cache.get(N);
if(B==null){
byteb=
binaryDigitsCalculator.calculateBinaryDigit(n);
cache.put(N,newByte(b));
returnb;
}else{
returnB.bytevalue();
}
}
}
这是很之前的完成PiBinaryDigitsCalculator的一种复杂的refactored版本.CachingBinaryDigitsCalculator包装了BinaryDigitsCalculator句柄,并增添了缓存,供calculateBinaryDigit的办法挪用.这类办法进步了代码的可读性与可保护性.用户不克不及间接利用BinaryDigitsCalculator接口来完成算法,以是,假如必要封闭缓存块,将是很简单完成的.
另有,符合的测试程序很简单写出来.好比,我们写一个假的BinaryDigitsCalculator完成,每次calculateBinaryDigit被挪用,付与不异的参数,前往分歧的值.如许,我们就可以测试缓存是不是事情了,由于假如每次都前往不异的值,则证实缓存是一般事情了.这类测试在之前那种复杂的完成是不成能的.
还得说上一点,就java本质而言,是面相对象的,但是你有没有发现,java也不全是,比如说基本类型,int,那他就是整型而不是对象,转换类型是还得借助包装类。 |
|