简体   繁体   中英

How can I remove duplicated code between classes without implements?

I wrote many implementations of a function to compute the Fibonacci number at a given position.

Fibonacci Class : this class helps me to test each implementation without rewrite same test code. I don't want to add " fibonacci(n - 2).add(fibonacci(n - 1)); " here because some implementations do not use it (imperative iteration, functional iteration).

public interface Fibonacci {
  BigInteger fibonacci(int n);

}

RecursiveFibonacci Class

public class SimpleRecursiveFibonacci implements Fibonacci{

  public BigInteger fibonacci(int n) {
    if(n < 2) {
      return BigInteger.ONE;             
    }

    return fibonacci(n - 2).add(fibonacci(n - 1));
  }
}

and MemorizedRecursiveFibonacci Class

public class MemoizedRecursiveFibonacci implements Fibonacci{
  private Map<Integer, BigInteger> cache = new HashMap<>();

  public BigInteger fibonacci(int n) {
    if(n < 2) {
      return BigInteger.ONE;
    }
    if(!cache.containsKey(n)){
      BigInteger currentFibonacci = fibonacci(n - 2).add(fibonacci(n - 1));
      cache.put(n, currentFibonacci);
    }

    return cache.get(n);
  }
}

As I see, there are some duplicated code in MemorizedRecursiveFibonacci Class

 if(n < 2) {
      return BigInteger.ONE;

and

  BigInteger currentFibonacci = fibonacci(n - 2).add(fibonacci(n - 1));

How can I keep it DRY? remove duplicated code?

The MemorizedRecursiveFibonacci can delegate to a RecursiveFibonacci instance:

public class MemoizedRecursiveFibonacci implements Fibonacci {
  SimpleRecursiveFibonacci simple = new SimpleRecursiveFibonacci();
  private Map<Integer, BigInteger> cache = new HashMap<>();

  public BigInteger fibonacci(int n) {
    if(!cache.containsKey(n)) {
      BigInteger currentFibonacci = simple.fibonacci(n);
      cache.put(n, currentFibonacci);
    }

    return cache.get(n);
  }
}

Or, even more elegantly, using Java 8's Map#computeIfAbsent :

public class MemoizedRecursiveFibonacci implements Fibonacci {
  SimpleRecursiveFibonacci simple = new SimpleRecursiveFibonacci();
  private Map<Integer, BigInteger> cache = new HashMap<>();

  public BigInteger fibonacci(int n) {
    return cache.computeIfAbsent(n, k -> simple.fibonacci(k));
}

What about an abstract common parent? Something like this:

public abstract class ParentFibonacci implements Fibonacci {
    protected BigInteger getFirstValues(int n) {
        if (n < 2) {
            return BigInteger.ONE;
        }
        return BigInteger.ZERO;
    }
}

This way your Fibonacci implementation need to implement Fibonacci.fibonacci(int n) and can use parent methods.

public class SimpleRecursiveFibonacci extends ParentFibonacci {

    public BigInteger fibonacci(int n) {
        if (n < 2) {
            return getFirstValues();
        }
        return fibonacci(n - 2).add(fibonacci(n - 1));
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM