KnusperPudding
KnusperPudding

Reputation: 412

Java Interface containing an empty Enum

I'm trying to prepare an interface i want to implement for Datamodel-Classes.
Therefor i want to use an enum inside the interface so i know i need to implement it later.
Example:

public interface MyModelInterface {

    public enum Field;

    public Object get(Field field);

    public void set(Field field, Object value);
}

The expected implementation:

public class MyModel implements MyModelInterface {


    public enum Field {

        ID("id"),
        Name1("Name1"),
        Name2("Name2");

        private String field;

        private Field(String field) {
            this.field = field;
        }
    }

    public Object get(Field field) {
        //...
    }


    public void set(Field field, Object value){
        //...
    }

    public static void main(String[] args) {
        MyModel myModel = new MyModel();
        System.out.println(myModel.get(MyModel.Field.ID));
        System.out.println(myModel.get(MyModel.Field.Name1));
    }
}

Since I don't know which fields the model will contain until I implement it. I did some research and figured that enum can't be extended, so i am aware of that. is there any way to archive this or any kind of workaround?

i don't want to use String Parameters on the getter/setter Methods to avoid using wrong values.

Thanks in advance for any suggestion.

Update:

So this is what worked for me: Splitting the interface/class in three parts, including an abstract class:

Interface:

public interface MyModelInterface<E extends Enum<E>> {

    public Object get(E field);

    public void set(E field, Object value);

}

Abstract Class:

public abstract class MyAbstractModel<E extends Enum<E>> implements MyModelInterface<E>{

    protected final EnumMap<E, Object> fields;

    public MyAbstractModel(Class<E> enumKlazz) {
        fields = new EnumMap<>(enumKlazz);
    }

    @Override
    public Object get(E field) {
        return fields.get(field);
    }

    @Override
    public void set(E field, Object value) {
        this.fields.put(field, value);
    }
}

Class(where i actually archive my goal):

public class MyModel extends MyAbstractModel<MyModel.Field> {

    public MyModel() {
        super(MyModel.Field.class);
    }

    public enum Field {

        ID("ID"),
        Name1("NAME1"),
        Name2("NAME2"),
        Age("AGE"),
        ;
        private final String field;

        private Field(String field) {
            this.field = field;
        }
        public String getName() {
            return field;
        }
    }

    public static void main(String[] args) {
        MyModel myModel = new MyModel();
        System.out.println(myModel.get(Field.Name1));
    }
}

Upvotes: 0

Views: 618

Answers (3)

Mena
Mena

Reputation: 48434

Interface fields are static and final implicitly.

What you could do is to have an interface method returning Enum<?>, and your classes implementing it.

For instance:

interface Foo {
    public Enum<?> getEnum();
}
class Bar implements Foo {
    enum Blah {
        INSTANCE;
    }

    public Enum<?> getEnum() {
        return Blah.INSTANCE;
    }
}

Edit

Not completely sure I understand your question update, but here's a solution that will de-couple returning a specific enum instance from an enum, by means of two interfaces.

The example is self-contained in a Main class.

public class Main {

    public static void main(String[] args) {
        System.out.println(new Bar().getEnumField().name());
    }
    static interface IHasEnum {
        public Enum<? extends IMyEnum> getEnumField();
    }
    static interface IMyEnum {
        public Enum<? extends IMyEnum> getField();
    }
    static class Bar implements IHasEnum {
        enum Blah implements IMyEnum {
            DEFAULT_INSTANCE,
            THE_FIELD;
            public Enum<? extends IMyEnum> getField() {
                return THE_FIELD;
            }
        }
        public Enum<? extends IMyEnum> getEnumField() {
            return Blah.DEFAULT_INSTANCE.getField();
        }

    }
}

Output

THE_FIELD

Note

The trick here is to add a "default" instance to the enum (DEFAULT_INSTANCE), so the getField method is an instance method, hence overriding the one declared in the IMyEnum interface.

Again, not entirely sure this addresses your issue.

Upvotes: 3

bbofosu
bbofosu

Reputation: 57

Java generics will be the best solution. Lets assume, you don't know the contents of the Field as mentioned.

Create a generic interface like this:

public interface MyModelInterface<T> {
    public T get();
}

Then create a class Field like this:

public class Field {
    private String id;
    private String name1;
    private String name2;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName1() {
        return name1;
    }

    public void setName1(String name1) {
        this.name1 = name1;
    }

    public String getName2() {
        return name2;
    }

    public void setName2(String name2) {
        this.name2 = name2;
    }
}

and then your model class will look like

public class MyModel implements MyModelInterface<Field> {
    @Override
    public Field get() {
        Field field = new Field();
        field.setId("ID");
        field.setName1("Name1");
        field.setName2("Name2");

       return field;
    }

    public static void main(String[] args) {
        MyModel myModel = new MyModel();
        System.out.println(myModel.get().getId());
        System.out.println(myModel.get().getName1());
        System.out.println(myModel.get().getName2());
    }
}

Upvotes: 0

Joop Eggen
Joop Eggen

Reputation: 109597

What you are describing is an EnumMap<E, T> - which functions like an array, with that same get-

public class MyModelBase<E extends Enum<E>> {
    private final Class<E> enumKlazz;
    private final EnumMap<E, Object> fields;

    public MyModelBase(Class<E> enumKlazz) {
        this.enumKlazz = enumKlazz;
        fields = new EnumMpa<>(enumKlazz);
    }

    public Object get(E field) {
         return fields.get(field);
    }

    public void set(E field, Object value) {
         fields.put(field, value);
    }
}

enum UserField { id, surname, name, age };
MyModelBase<UserField> userModel = new MyModelBase<>(UserField.class);
userModel.set(UserField.surname, "X");

Because of type erasure the enum map needs the class. Above the enum class is also stored as field, as some static Enum methods need the enum class. For iterating, and so on.

Upvotes: 1

Related Questions