使用枚举选择内部实现
Using enum to choose internal implementation
任务:有一个 class 以不同的方式实现某些东西。 class 的用户应该只看到代表可用选项的 public enum
,同时隐藏不同行为的所有实现。
为了避免在每次调用方法时检查提供的 "style",构造函数对提供的枚举值使用 switch
以将适当的内部私有 class 分配给字段。
这里是 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.
为什么要绑定枚举?使用多态性可以轻松实现您所描述的内容。如果以后担心扩展,可以使用Factory或者Decorator等设计模式。
除了将枚举用作工厂开关的常量之外,您还可以通过为枚举常量配备任一配置来避免开关
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();
}
任务:有一个 class 以不同的方式实现某些东西。 class 的用户应该只看到代表可用选项的 public enum
,同时隐藏不同行为的所有实现。
为了避免在每次调用方法时检查提供的 "style",构造函数对提供的枚举值使用 switch
以将适当的内部私有 class 分配给字段。
这里是 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.
为什么要绑定枚举?使用多态性可以轻松实现您所描述的内容。如果以后担心扩展,可以使用Factory或者Decorator等设计模式。
除了将枚举用作工厂开关的常量之外,您还可以通过为枚举常量配备任一配置来避免开关
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();
}