【问题标题】:Using enum to choose internal implementation使用枚举选择内部实现
【发布时间】:2015-11-06 11:46:01
【问题描述】:

任务:有一个以不同方式实现某些东西的类。类的用户应该只看到代表可用选项的public enum,同时隐藏不同行为的所有实现。

为避免在每次调用方法时检查提供的“样式”,构造函数在提供的枚举值上使用switch 以将适当的内部私有类分配给字段。

这里是 SSCCE:

public class Greeter {
    public enum GreetingStyle { HEY, HELLO }

    private String name;
    private GreetingChooser greetingChooser;
    public Greeter(String name, GreetingStyle style) {
        this.name = name;
        switch(style) {
            case HEY:
                greetingChooser = new Hey();
                break;
            case HELLO:
                greetingChooser = new Hello();
                break;
            default :
                throw new UnsupportedOperationException("GreetingStyle value not handled : " + style.toString());
        }
    }

    public void greet() {
        // need to avoid switch(style) here
        System.out.println(greetingChooser.greeting() + ", " + name + "!");
    }

    // this interface can't be public
    private interface GreetingChooser {
        String greeting();
    }

    private class Hey implements GreetingChooser {
        public String greeting() {
            return "Hey";
        }
    }

    private class Hello implements GreetingChooser {
        public String greeting() {
            return "Hello";
        }
    }

    public static void main(String args[]) {
        new Greeter("John Doe", Greeter.GreetingStyle.HEY).greet();
        new Greeter("John Doe", Greeter.GreetingStyle.HELLO).greet();
    }
}

问题:实现这样的功能以使其将来可维护是否是一种好方法(例如,我们需要添加GreetingStyle ALOHA)?我的另一个想法是使用静态地图

private static final Map<GreetingStyle, GreetingChooser> greetingMap;
static {
    greetingMap = new HashMap<>();
    greetingMap.put(Greeter.GreetingStyle.HEY, new Hey());
    greetingMap.put(Greeter.GreetingStyle.HELLO, new Hello());
}

并在构造函数中使用greetingMap.get(style)

注意:在 Java 8 中,最好使用 lambdas 实现(如果接口只有一个函数),但我受限于 Java 7。

【问题讨论】:

  • 您可以将greet 作为抽象放在enum 中,并以GreetingStyle.HEY.greet("JohnDoe") 结尾,例如参见answer

标签: java constructor enums public


【解决方案1】:

除了使用枚举作为工厂切换的常量之外,您还可以通过为枚举常量配备任一配置来避免切换

public enum GreetingStyle 
{ 
    HEY("Hey"),
    HELLO("Hello");

    GreetingStyle(String text) {
        this.text = text;
    }

    public final String text;
}

或行为:

public enum GreetingStyle 
{ 
    HEY {
        public void greet() { /* performs hey style greeting*/ }
    },
    HELLO{
        public void greet() { /* performs hello style greeting*/ }
    };

    public abstract void greet();
}

【讨论】:

  • 但这会使greet 公开。 Java 似乎不允许在枚举中使用私有抽象方法。
  • @andrybak 这可能是也可能不是问题,具体取决于具体情况。
  • 仍然很奇怪,Java 允许内部类中的私有方法可供外部类访问,但不允许内部枚举中的私有方法。 编辑:问题是我们不能覆盖子类中的私有方法,而枚举只是构建隐藏类层次结构的语法糖。
【解决方案2】:

为什么要绑定到枚举?您所描述的可以使用多态性轻松实现。如果您担心将来扩展它,您可以使用工厂或装饰器等设计模式。

【讨论】:

  • 只有 enum 是公开的,对类的用户隐藏实现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-07
  • 1970-01-01
  • 1970-01-01
  • 2011-07-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多