Why would an Enum implement an Interface?

前端 未结 16 2710
长发绾君心
长发绾君心 2020-11-28 01:34

I just found out that Java allows enums to implement an interface. What would be a good use case for that?

相关标签:
16条回答
  • 2020-11-28 01:59

    When creating constants in a jar file, it is often helpful to let users extend enum values. We used enums for PropertyFile keys and got stuck because nobody could add any new ones! Below would have worked much better.

    Given:

    public interface Color {
      String fetchName();
    }
    

    and:

    public class MarkTest {
    
      public static void main(String[] args) {
        MarkTest.showColor(Colors.BLUE);
        MarkTest.showColor(MyColors.BROWN);
      }
    
      private static void showColor(Color c) {
        System.out.println(c.fetchName());
      }
    }
    

    one could have one enum in the jar:

    public enum Colors implements Color {
      BLUE, RED, GREEN;
      @Override
      public String fetchName() {
        return this.name();
      }
    }
    

    and a user could extend it to add his own colors:

    public enum MyColors implements Color {
      BROWN, GREEN, YELLOW;
      @Override
      public String fetchName() {
        return this.name();
      }
    }
    
    0 讨论(0)
  • 2020-11-28 02:00

    Another posibility:

    public enum ConditionsToBeSatisfied implements Predicate<Number> {
        IS_NOT_NULL(Objects::nonNull, "Item is null"),
        IS_NOT_AN_INTEGER(item -> item instanceof Integer, "Item is not an integer"),
        IS_POSITIVE(item -> item instanceof Integer && (Integer) item > 0, "Item is negative");
    
        private final Predicate<Number> predicate;
        private final String notSatisfiedLogMessage;
    
        ConditionsToBeSatisfied(final Predicate<Number> predicate, final String notSatisfiedLogMessage) {
            this.predicate = predicate;
            this.notSatisfiedLogMessage = notSatisfiedLogMessage;
        }
    
        @Override
        public boolean test(final Number item) {
            final boolean isNotValid = predicate.negate().test(item);
    
            if (isNotValid) {
                log.warn("Invalid {}. Cause: {}", item, notSatisfiedLogMessage);
            }
    
            return predicate.test(item);
        }
    }
    

    and using:

    Predicate<Number> p = IS_NOT_NULL.and(IS_NOT_AN_INTEGER).and(IS_POSITIVE);
    
    0 讨论(0)
  • 2020-11-28 02:01

    The post above that mentioned strategies didn't stress enough what a nice lightweight implementation of the strategy pattern using enums gets you:

    public enum Strategy {
    
      A {
        @Override
        void execute() {
          System.out.print("Executing strategy A");
        }
      },
    
      B {
        @Override
        void execute() {
          System.out.print("Executing strategy B");
        }
      };
    
      abstract void execute();
    }
    

    You can have all your strategies in one place without needing a separate compilation unit for each. You get a nice dynamic dispatch just with:

    Strategy.valueOf("A").execute();
    

    Makes java read almost like a nice loosely typed language!

    0 讨论(0)
  • 2020-11-28 02:02

    One of the best use case for me to use enum's with interface is Predicate filters. It's very elegant way to remedy lack of typness of apache collections (If other libraries mayn't be used).

    import java.util.ArrayList;
    import java.util.Collection;
    
    import org.apache.commons.collections.CollectionUtils;
    import org.apache.commons.collections.Predicate;
    
    
    public class Test {
        public final static String DEFAULT_COMPONENT = "Default";
    
        enum FilterTest implements Predicate {
            Active(false) {
                @Override
                boolean eval(Test test) {
                    return test.active;
                }
            },
            DefaultComponent(true) {
                @Override
                boolean eval(Test test) {
                    return DEFAULT_COMPONENT.equals(test.component);
                }
            }
    
            ;
    
            private boolean defaultValue;
    
            private FilterTest(boolean defautValue) {
                this.defaultValue = defautValue;
            }
    
            abstract boolean eval(Test test);
    
            public boolean evaluate(Object o) {
                if (o instanceof Test) {
                    return eval((Test)o);
                }
                return defaultValue;
            }
    
        }
    
        private boolean active = true;
        private String component = DEFAULT_COMPONENT;
    
        public static void main(String[] args) {
            Collection<Test> tests = new ArrayList<Test>();
            tests.add(new Test());
    
            CollectionUtils.filter(tests, FilterTest.Active);
        }
    }
    
    0 讨论(0)
  • 2020-11-28 02:03

    Here's one example (a similar/better one is found in Effective Java 2nd Edition):

    public interface Operator {
        int apply (int a, int b);
    }
    
    public enum SimpleOperators implements Operator {
        PLUS { 
            int apply(int a, int b) { return a + b; }
        },
        MINUS { 
            int apply(int a, int b) { return a - b; }
        };
    }
    
    public enum ComplexOperators implements Operator {
        // can't think of an example right now :-/
    }
    

    Now to get a list of both the Simple + Complex Operators:

    List<Operator> operators = new ArrayList<Operator>();
    
    operators.addAll(Arrays.asList(SimpleOperators.values()));
    operators.addAll(Arrays.asList(ComplexOperators.values()));
    

    So here you use an interface to simulate extensible enums (which wouldn't be possible without using an interface).

    0 讨论(0)
  • 2020-11-28 02:04

    It's required for extensibility -- if someone uses an API you've developed, the enums you define are static; they can't be added to or modified. However, if you let it implement an interface, the person using the API can develop their own enum using the same interface. You can then register this enum with an enum manager which conglomerates the enums together with the standard interface.

    Edit: @Helper Method has the perfect example of this. Think about having other libraries defining new operators and then telling a manager class that 'hey, this enum exists -- register it'. Otherwise, you'd only be able to define Operators in your own code - there'd be no extensibility.

    0 讨论(0)
提交回复
热议问题