How do I define a generic member variable in an enum?
I want to reference an enum method to retrieve the class of an algorithm so that I can lazy-load a new instance of the algorithm for use in the strategy design pattern.
In this example, I am using an enum to reference three different strategy classes that calculate Fibonacci numbers: RecursiveFibonacciGenerator
, IterativeFibonacciGenerator
, and MemoizedFibonacciGenerator
(all of which inherit from FibonacciGenerator
).
The code (with lines generating errors commented with intent) is as follows:
package com.example.strategy;
public class Fibonacci {
private enum Algorithm {
RECURSIVE (RecursiveFibonacciGenerator.class),
ITERATIVE (IterativeFibonacciGenerator.class),
MEMOIZED (MemoizedFibonacciGenerator.class);
private final Class<T> algorithmClass; // Declare class of same type as constructor
开发者_JAVA百科 private final T instance; // Declare instance of class defined in constructor
private <T extends FibonacciGenerator> Algorithm(Class<T> algorithmClass) {
this.algorithmClass = algorithmClass;
}
public T getInstance() {
if (this.instance == null) {
this.instance = this.algorithmClass.newInstance();
}
return this.instance;
}
}
public Integer getTerm(Integer termNumber) {
profileGenerator(termNumber, Algorithm.RECURSIVE);
profileGenerator(termNumber, Algorithm.ITERATIVE);
return profileGenerator(termNumber, Algorithm.MEMOIZED);
}
private Integer profileGenerator(Integer termNumber, Algorithm algorithm) {
System.out.print("Computing term using " + algorithm.toString() + " algorithm... ");
Long startTimeMilliseconds = System.currentTimeMillis();
Integer term = algorithm.getInstance().generateTerm(termNumber);
Long endTimeMilliseconds = System.currentTimeMillis();
Long computationTimeMilliseconds = endTimeMilliseconds - startTimeMilliseconds;
System.out.println("term computed in " + computationTimeMilliseconds + " milliseconds");
}
}
I would like to know how I can use this enum
constructor to store a member variable of the Class<T>
type.
Edit: Added full code to clarify intent
public enum Algorithm {
RECURSIVE(FibonacciGenerator.RecursiveFibonacciGenerator.class),
ITERATIVE(FibonacciGenerator.IterativeFibonacciGenerator.class),
MEMOIZED(FibonacciGenerator.MemoizedFibonacciGenerator.class);
private final Class<? extends FibonacciGenerator> algorithmClass;
private <T extends FibonacciGenerator> Algorithm(Class<T> algorithmClass) {
this.algorithmClass = algorithmClass;
}
}
Does that do what you want?
The other option is to use an instance of the class, but after further thought I think this is a bad idea. If you are going to use an instance of the class then why'd you need the enum in the first place?
Try providing a real instance instead of class:
public enum Algorithm {
RECURSIVE (new RecursiveFibonacciGenerator()),
ITERATIVE (new IterativeFibonacciGenerator()),
MEMOIZED (new MemoizedFibonacciGenerator());
private <T extends FibonacciGenerator> Algorithm(T algorithm) {}
}
Plouh is right. And you may declare and initialize a member variable just as if it were a class rather than an enum:
private final FibonacciGenerator _instance;
private Algorithm(FibonacciGenerator instance) {
_instance = instance;
}
and then return it through a public getFibonacciGenerator() method. Notice that there is no need to use generics if you store the instance rather than the Class. And remember to declare the field as "final"
I am not sure if i understand well the question, but if you simply want to keep the strategy as member variable:
public enum Algorithm {
RECURSIVE (RecursiveFibonacciGenerator.class),
ITERATIVE (IterativeFibonacciGenerator.class),
MEMOIZED (MemoizedFibonacciGenerator.class);
private Class<? extends FibonacciGenerator> strategy;
private Algorithm(Class<? extends FibonacciGenerator> algorithmClass) {
this.strategy = algorithmClass;
}
Class<? extends FibonacciGenerator> getStrategy() {
return strategy;
}
}
I ended up with the following code:
package com.example.strategy;
public class Fibonacci {
private enum Algorithm {
UNDEFINED (null),
RECURSIVE (RecursiveFibonacciGenerator.class),
ITERATIVE (IterativeFibonacciGenerator.class),
MEMOIZED (MemoizedFibonacciGenerator.class);
private final Class<? extends FibonacciGenerator> algorithmClass;
private FibonacciGenerator instance;
private <T extends FibonacciGenerator> Algorithm(Class<T> algorithmClass) {
this.algorithmClass = algorithmClass;
}
public FibonacciGenerator getInstance() {
if (this.instance == null) {
try {
this.instance = this.algorithmClass.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return this.instance;
}
}
public Integer getTerm(Integer termNumber) {
return profileGenerator(termNumber, Algorithm.MEMOIZED);
}
private Integer profileGenerator(Integer termNumber, Algorithm algorithm) {
System.out.print("Computing term using " + algorithm.toString() + " algorithm... ");
Long startTimeMilliseconds = System.currentTimeMillis();
Integer term = algorithm.getInstance().generateTerm(termNumber);
Long endTimeMilliseconds = System.currentTimeMillis();
Long computationTimeMilliseconds = endTimeMilliseconds - startTimeMilliseconds;
System.out.println("term computed in " + computationTimeMilliseconds + " milliseconds");
return term;
}
}
精彩评论