Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 563
Andrew Avatar asked Jan 19 '23 14:01

Andrew


2 Answers

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?

like image 193
Jeff Foster Avatar answered Jan 30 '23 23:01

Jeff Foster


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) {}
}
like image 28
plouh Avatar answered Jan 30 '23 23:01

plouh