国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

用Java動態(tài)代理類實現(xiàn)記憶功能

2019-11-18 10:41:42
字體:
供稿:網(wǎng)友

  記憶是衍生自Lisp,Python,和Perl等過程性語言的一種設(shè)計模式,它可以對前次的計算結(jié)果進(jìn)行記憶。 一個實現(xiàn)了記憶功能的函數(shù), 帶有顯式的cache, 所以, 已經(jīng)計算過的結(jié)果就能直接從cache中獲得, 而不用每次都進(jìn)行計算.

  記憶能顯著的提升大計算量代碼的效率. 而且是一種可重用的方案.

  本文闡述了在java中使用這一模式的方法,并提供了一個可以提供上述功能的"記憶類":

Foo foo = (Foo) Memoizer.memoize(new FooImpl());

  這里,Foo是一個接口,它含有的方法是需要記憶的.FooImpl是Foo的一個實現(xiàn).foo是Foo的一個引用.方法與FooImpl基本相同,區(qū)別在于Foo返回的值,會被緩存起來.單個記憶類的優(yōu)點在于為任何類添加記憶功能是很簡單的:定義一個包含需要記憶的方法的接口,然后調(diào)用memoize來實現(xiàn)一個實例.

  為了理解記憶類是怎么實現(xiàn)的,我們將分幾步來解釋.首先,我解釋一下為何緩存能夠在需要它的類中實現(xiàn).然后,我測試一下如何為一個特定的類添加緩存包裝器.最后,我解釋一下如何才能使得一個緩存包裝器能夠通用于任意的類.

  為大計算量的程序添加緩存
 
  作為一個大計算量程序的例子,我們考慮PiBinaryDigitsCalculator這個例子-計算二進(jìn)制數(shù)據(jù)pi.僅有的public方法calculateBinaryDigit帶有一個參數(shù):整數(shù)n,代表需要精確到的位數(shù).例如,1000000,將會返回小數(shù)點后的一百萬位,通過byte值返回-每位為0或者1.

public class PiBinaryDigitsCalculator {
/**
* Returns the coefficient of 2^n in the binary
* eXPansion of pi.
* @param n the binary digit of pi to calculate.
* @throws ValidityCheckFailedException if the validity
* check fails, this means the implementation is buggy
* or n is too large for sufficient PRecision to be
* retained.
*/
public byte calculateBinaryDigit(final int n) {
return runBBPAlgorithm(n);
}

private byte runBBPAlgorithm(final int n) {
// Lengthy routine goes here ...
}

}
  最簡單直接的方法來緩存返回值可以通過修改這個類來實現(xiàn):添加一個Map來保存之前計算得到的值,如下:

import java.util.HashMap;

public class PiBinaryDigitsCalculator {
private HashMap cache = new HashMap();
public synchronized byte calculateBinaryDigit(
final int n) {
final Integer N = new Integer(n);
Byte B = (Byte) cache.get(N);
if (B == null) {
byte b = runBBPAlgorithm(n);
cache.put(N, new Byte(b));
return b;
} else {
return B.bytevalue();
}
}
private byte runBBPAlgorithm(final int n) {
// Lengthy routine goes here ...
}
}
  calculateBinaryDigit方法首先會檢查HashMap里面是否緩存了這個要害字-參數(shù)n,假如找到了,就直接返回這個值.否則,就會進(jìn)行這個冗長的計算,并將結(jié)果保存到緩存里面.在添加進(jìn)HashMap的時候,在原始類型和對象之間還要進(jìn)行小小的轉(zhuǎn)換.

  盡管這個方法是可行的,但是有幾個缺點.首先,進(jìn)行緩存的代碼和正常的算法代碼不是顯著分開的.一個類,不僅負(fù)責(zé)進(jìn)行計算,也要負(fù)責(zé)進(jìn)行維護(hù)緩存數(shù)據(jù).這樣,要進(jìn)行一些測試就會顯得很困難.比如,不能寫一個測試程序來測試這個算法持續(xù)地返回相同的值,因為,從第二次開始,結(jié)果都是直接從cache中獲得了.

  其次,當(dāng)緩存代碼不再需要,移除它會變得困難,因為它和算法塊地代碼是緊密結(jié)合在一起的.所以,要想知道緩存是否帶來了很高的效率提升也是很困難的,因為不能寫一個測試程序是和緩存數(shù)據(jù)分開的.當(dāng)你改進(jìn)了你的算法,緩存有可能失效-但是這個時候你并不知道.

  第三,緩存代碼不能被重用.盡管代碼遵從了一個普通的模式,但是都是在一個類- PiBinaryDigitsCalculator里面.

  前面兩個問題都可以通過構(gòu)造一個緩存包裝器來解決.
  緩存包裝器

  通過使用Decorator模式,要分開計算代碼和緩存代碼是很輕易的.首先,定義一個接口,里面定義基本的方法.

public interface BinaryDigitsCalculator {

public byte calculateBinaryDigit(final int n);
}
  然后定義兩個實現(xiàn),分別負(fù)責(zé)兩個任務(wù):

public class PiBinaryDigitsCalculator
implements BinaryDigitsCalculator {

public byte calculateBinaryDigit(final int n) {
return runBBPAlgorithm(n);
}

private byte runBBPAlgorithm(final int n) {
// Lengthy routine goes here ...
}

}

import java.util.HashMap;

public class CachingBinaryDigitsCalculator implements
BinaryDigitsCalculator {

private BinaryDigitsCalculator binaryDigitsCalculator;
private HashMap cache = new HashMap();

public CachingBinaryDigitsCalculator(
BinaryDigitsCalculator calculator) {
this.binaryDigitsCalculator = calculator;
}

public synchronized byte calculateBinaryDigit(int n) {
final Integer N = new Integer(n);
Byte B = (Byte) cache.get(N);
if (B == null) {
byte b =
binaryDigitsCalculator.calculateBinaryDigit(n);
cache.put(N, new Byte(b));
return b;
} else {
return B.bytevalue();
}
}
}
  這是很之前的實現(xiàn)PiBinaryDigitsCalculator的一種簡單的refactored版本. CachingBinaryDigitsCalculator包裝了BinaryDigitsCalculator句柄,并增加了緩存,供calculateBinaryDigit的方法調(diào)用. 這種方法提高了代碼的可讀性與可維護(hù)性. 用戶不能直接使用BinaryDigitsCalculator接口來實現(xiàn)算法,所以,假如需要關(guān)閉緩存塊,將是很輕易實現(xiàn)的.

  還有,合適的測試程序很輕易寫出來.比如,我們寫一個假的BinaryDigitsCalculator實現(xiàn),每次calculateBinaryDigit被調(diào)用,賦予相同的參數(shù),返回不同的值. 這樣,我們就能測試緩存是否工作了,因為假如每次都返回相同的值,則證實緩存是正常工作了. 這種測試在之前那種簡單的實現(xiàn)是不可能的。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 南澳县| 西峡县| 曲麻莱县| 阿坝县| 灵璧县| 开鲁县| 长汀县| 吉安市| 石渠县| 织金县| 韶关市| 安乡县| 荣昌县| 通江县| 华池县| 平和县| 溧水县| 霍林郭勒市| 万安县| 临桂县| 长海县| 隆昌县| 龙门县| 巩留县| 登封市| 修水县| 浦城县| 建平县| 瑞安市| 安丘市| 桦川县| 沛县| 东光县| 盐池县| 花垣县| 克拉玛依市| 宁阳县| 定西市| 松江区| 华安县| 永嘉县|