Java uses dynamic proxy classes to achieve memory function

xiaoxiao2021-03-06  121

Memory is a design pattern derived from process language such as Lisp, Python, and Perl, which can be memorized for the previous calculation results. A function that implements a memory function, with explicit Cache, so the result has been calculated directly from cache without each calculation. Memory can significantly improve the efficiency of large computing amount code. And it is a reusable solution. This article describes the method of using this mode in Java, and provides a "memory class" that provides the above functions: foo foo = (foo) Memoizer.Memoize (New fooiMPL () Here, the foo is an interface, which is a way to be remembered. FooIMPL is an implementation of FOO. FOO is a reference to the foo. The method is basically the same as FooIMPL, the difference between the Foo returned, will be cached. The advantage of a single memory class is that it is very simple to add a memory function for any class: Define an interface that contains methods that requires memory, then calls Memoize to implement an instance. In order to understand how the memory class is implemented, we will take a few steps. Explanation. First, I explain why the cache can be implemented in a class that needs it. Then I test how to add a cache wrapper for a specific class. Finally, I explain how to make a cache wrapper can be used for arbitrary Class. Adding a cache for large computing quantities as an example of a large computing quantity program, we consider PibinaryDigitscalculator this example - calculate binary data Pi. Only public method CalculateBinaryDigit has a parameter: integer n, representative needs to be accurate Number. For example, 100,00000, will return one million bits after the decimal point, return through the BYTE value - per bit is 0 or 1. (algorithm can be referenced:

Http://www.cecm.sfu.ca/~pborwein/papers/p123.pdf

)

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. ..}}

The simplest method to cache the return value can be implemented by modifying this class: adding a map to save the previously calculated value, as follows:

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) {// Length Routine Goes Here ...} CalculateBinaryDigit method first checks if this keyword is cached in HashMap, if found, return this value directly. Otherwise, this will be conducted. Length of lengthy calculations and saves the results into the cache. Small conversions must be performed between the original type and object when adding HashMap.

Although this method is feasible, there are several shortcomings. First, the cached code and normal algorithm code are not significantly separated. A class is not only responsible for calculation, but also to maintain cache data. This way, to do some Testing will be very difficult. For example, you cannot write a test program to test this algorithm to continuously return the same value, because from the second start, the result is directly from cache.

Second, when the cache code is no longer needed, it will become difficult because it is closely combined with the algorithm block code. So, if you want to know if the cache has brought high efficiency improvement is also very difficult. Because you can't write a test program is separated from the cache data. When you improve your algorithm, the cache may fail - but you don't know this time.

Third, the cache code cannot be reused. Although the code complies with a normal mode, it is in a class - PibinaryDigitscalculator.

The front two problems can be solved by constructing a cache wrapper.

Cache wrapper

By using the Decorator mode, it is easy to separate computing code and cache code. First, define an interface and define a basic method.

Public interface binarydigitscalculator {public Byte CalculateBinaryDigit (Final Int n);}

Then define two implementations, which are responsible for both tasks:

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 implementsBinaryDigitsCalculator {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 = binarydigitscalcalculator.calculatebinarydigit (n); cache.put (n, new byte (b)); return b;} else { Return B.Bytevalue ();}}} This is a simple Refactored version of the implementation of PibinaryDigitscalculator. CACHINGDIGITSCALCALCULATOR Package BinaryDigitscalculator The Digitscalculator handle and adds a cache to CalculateBinaryDigit method call. This method improves the readability and maintainability of the code. Users cannot use the BinaryDigitscalculator interface to implement algorithms, so if you need to turn off the cache block, it will be very Easy to implement.

Also, the appropriate test program is easy to write. For example, we write a fake binarydigitscalculator implementation, each calculatebinarydigit is called, give the same parameters, returns different values. In this way, we can test whether the cache is working, because If the same value is returned each time, the cache is working properly. This simple implementation is impossible in this test.

About translation

Chris, passionate Java game engine technology, JVM technology, active in the JXTA community. You can click: http://www.matrix.org.cn/user_view.asp? usrname = chris View His personal information

Ezerg Programming

转载请注明原文地址:https://www.9cbs.com/read-99769.html

New Post(0)