简体   繁体   English

如何在枚举中定义泛型成员变量?

[英]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.我想引用一个枚举方法来检索算法的 class 以便我可以延迟加载算法的新实例以用于策略设计模式。

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 ).在此示例中,我使用枚举来引用计算 Fibonacci 数的三个不同策略类: RecursiveFibonacciGeneratorIterativeFibonacciGeneratorMemoizedFibonacciGenerator (所有这些都继承自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.我想知道如何使用这个enum构造函数来存储Class<T>类型的成员变量。

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.另一种选择是使用 class 的实例,但经过进一步思考,我认为这是一个坏主意。 If you are going to use an instance of the class then why'd you need the enum in the first place?如果您要使用 class 的实例,那么为什么首先需要枚举?

Try providing a real instance instead of class:尝试提供一个真实实例而不是 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:你可以声明和初始化一个成员变量,就好像它是一个 class 而不是一个枚举:

private final FibonacciGenerator _instance;

private Algorithm(FibonacciGenerator instance) {
    _instance = instance;
}

and then return it through a public getFibonacciGenerator() method.然后通过公共的 getFibonacciGenerator() 方法返回它。 Notice that there is no need to use generics if you store the instance rather than the Class.请注意,如果您存储实例而不是 Class,则无需使用 generics。 And remember to declare the field as "final"并记住将字段声明为“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;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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