简体   繁体   中英

Enums to implement different methods in Java

Suppose I constructed the following class

public enum OptimizationAlgorithmType {

    VANILLA(new HashMap<String, Double>()) {

        private final static String ETA = "eta";
        private Double eta = null;

        public OptimizationAlgorithmType setEta(Double eta) {
            this.eta = eta;
            return this;
        }

        @Override
        public Map<String, Double> getHyperarameters() {
            this.map.put(ETA, eta);
            return this.map;
        }       
    }, 

    MOMENTUM(new HashMap<String, Double>()) {

        private final static String ALPHA = "alpha";
        private final static String BETA = "beta";

        private Double alpha = null;
        private Double beta = null;

        public OptimizationAlgorithmType setAlpha(Double alpha) {
            this.alpha = alpha;
            return this;
        }

        public OptimizationAlgorithmType setBeta(Double beta) {
            this.beta = beta;
            return this;
        }

        @Override
        public Map<String, Double> getHyperarameters() {
            this.map.put(ALPHA, alpha);
            this.map.put(BETA, beta);
            return this.map;
        }
    };

    protected Map<String, Double> map;

    private OptimizationAlgorithmType(Map<String, Double> map) {
        this.map = map;
    }

    public abstract Map<String, Double> getHyperarameters();    
}

My goal was to construct an API that when I select a specif Enum then different methods would be available. For example

MultiThreadBackpropagation backpropagation = new MultiThreadBackpropagation(feedForward)
        .setNumberThreads(10)
        .setBatch(5)
        .setEpochs(100)
        .setOptimizer(OptimizationAlgorithmType.VANILLA.setEta(0.001));

Or

MultiThreadBackpropagation backpropagation = new MultiThreadBackpropagation(feedForward)
        .setNumberThreads(10)
        .setBatch(5)
        .setEpochs(100)
        .setOptimizer(OptimizationAlgorithmType.MOMENTUM.setAlpha(0.01).setBeta(0.99));

Unfortunately, this is not allowed. The ide warns about the unused methods (ie: setEta() )- and the methods are not available at all to select from the specific enum.

Is there a trick I can use to get the desired API?

Thanks

Edit Added an alternative answer below

I came up with some better

First an interface, then the two parameter classes that implement the interface

public interface Hyperparameter {...}   

public enum VanillaParameter implements Hyperparameter {
        ETA {

            @Override
            public Double getValue() {
                return this.etaValue;
            }

            @Override
            public void setValue(Double value) {

                if (value == null) {
                    throw new IllegalStateException("Parameter value cannot be set to null!");
                }
                this.etaValue = value;
            }
        };
        protected Double etaValue = 0.005;
    }

    public enum MomentumParameter implements Hyperparameter {
    ...
    }

Now add the main enum class

    public enum OptimizationType {

        VANILLA{
            private VanillaParameter eta = VanillaParameter.ETA;

            @Override
            public Hyperparameter get(Hyperparameter parameter) {
                switch ((VanillaParameter) parameter) {
                case ETA: return this.eta;
                }
                return null;
            }

            @Override
            public OptimizationType set(Hyperparameter parameter, Double value) {

                switch ((VanillaParameter) parameter) {
                case ETA: 
                    this.eta.setValue(value);
                    break;
                }
                return OptimizationType.VANILLA;
            }
        },
        ...
}

And the API looks really nice in my opinion and resembles my initial intention. Look forward to suggestions

MultiThreadBackpropagation backpropagation = new MultiThreadBackpropagation.BackpropagationBuilder(feedForward)
        .setBatch(5)
        .setEpochs(100)
        .setThreads(10)
        .setOptimizer(OptimizationType.MOMENTUM
                .set(MomentumParameter.ALPHA, 0.001)
                .set(MomentumParameter.BETA, 0.92))
        .build();

maybe try something like:

import java.util.Arrays;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.TreeSet;

public class So54067082enums_to_implement_different_methods_in_java {
    enum Type {
        vanilla(new TreeSet<>(Arrays.asList(new String[] {"eta"}))),
        momentum(new TreeSet<>(Arrays.asList(new String[] {"alpha","beta"})));
        Type(Set<String> names) {
            this.names=names;

        }
        final Set<String> names;
    }
    static class ParameterSet {
        ParameterSet(Type type) {
            this.type=type;
        }
        Double get(String name) {
            if(type.names.contains(name))
                return map.get(name);
            else throw new RuntimeException("oops");
        }
        void set(String name,Double value) {
            if(type.names.contains(name))
                map.put(name,value);
            else throw new RuntimeException("oops");
        }
        @Override public String toString() {
            return "ParameterSet [type="+type+", map="+map+"]";
        }
        final Type type;
        private final SortedMap<String,Double> map=new TreeMap<>();

    }
    public static void main(String[] args) {
        ParameterSet parameterSet=new ParameterSet(Type.vanilla);
        parameterSet.set("eta",.01);
        System.out.println(parameterSet);
        ParameterSet parameterSet2=new ParameterSet(Type.momentum);
        parameterSet2.set("alpha",.1);
        parameterSet2.set("beta",.9);
        System.out.println(parameterSet2);
    }
}

I don't see why you couldn't just use a less naive approach to the problem:

class OptimizationAlgorithm {
  public static class Vanilla implements OptimizationAlgorithm {
    public Vanilla setAlpha(float a) {
      return this;
    }

    public Vanilla setBeta(float a) {
      return this;
    }
  }

  public static Vanilla vanilla() { return new Vanilla(); }
}

backpropagation.setOptimizer(OptimizationAlgorithm.vanilla().setAlpha(0.05f).setBeta(0.10f));

A lot less boilerplate code, no mutable static instances problem and basically the same interface from the outside.

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