Search code examples
javaenums

Forcing enum implementors to contain certain elements


I am trying to do the following:

public interface Type
{
    // somehow force implementors to have:
    // ONE;
    // TWO;

    public String getName();
}

public enum Type_A implements Type
{
    ONE("A Is One"),
    TWO("A Is Two");

    private String name;

    private Type_A( String name_in )
    {
        name = name_in;
    }

    @Override
    public String getName()
    {
        return name;
    }
}

public enum Type_B implements Type
    {
        ONE("B Is One"),
        TWO("B Is Two");

        private String name;

        private Type_B(String name_in)
        {
            name = name_in;
        }

        @Override
        public String getName()
        {
            return name;
        }
    }

So that I can do the following:

 {
    Type type = Type_A;

    type.ONE.getName();
  }

I have not been able to do this.

I would guess I need an interface which is specific to enum?

// ignore the following so I can get past the "too much code" filter


Solution

  • I'd use the visitor pattern. That allows you to ensure that the classes which provide the per-enum value behaviour don't miss providing behaviour for any of the enum values, even when new values are added, while not requiring more than one enum type:

    package com.example.so;
    
    import java.util.Random;
    
    public class Eg {
        public static void main(String[] args) {
            Type.Visitor<String> nameVisitorA = new Type.Visitor<>() {
                @Override
                public String visitONE() {
                    return "A is ONE";
                }
    
                @Override
                public String visitTWO() {
                    return "A is TWO";
                }
            };
            Type.Visitor<String> nameVisitorB = new Type.Visitor<>() {
                @Override
                public String visitONE() {
                    return "B is ONE";
                }
    
                @Override
                public String visitTWO() {
                    return "B is TWO";
                }
            };
            Type.Visitor<String> theNameVisitor = new Random().nextBoolean() ? nameVisitorA : nameVisitorB;
            System.out.println(Type.ONE.accept(theNameVisitor));
            System.out.println(Type.TWO.accept(theNameVisitor));
        }
    }
    
    
    
    enum Type {
    
        ONE {
            @Override
            public <T> T accept(Visitor<T> visitor) {
                return visitor.visitONE();
            }
        },
        TWO {
            @Override
            public <T> T accept(Visitor<T> visitor) {
                return visitor.visitTWO();
            }
        };
    
        interface Visitor<T> {
            T visitONE();
            T visitTWO();
        }
        public abstract <T> T accept(Visitor<T> visitor);
    }
    

    This example randomly chooses a Type.Visitor instance and stores a reference to it in a variable which is then used to print the names of the enum values.