【发布时间】:2013-06-06 19:06:00
【问题描述】:
在处理一个项目时,我被要求设计一组类来实现定义一个简单操作的接口。通常这些类会以特定的顺序一次性完成它们的工作,但也可以只从其中一个类调用方法。
考虑到以上所有因素并考虑到: - 每个类都有相当基本的逻辑 - 不需要扩展另一个类 - 将所有类放在一个文件中可能会很方便 - 在需要时编辑源文件不是问题
我想出了以下解决方案(实际的类并没有那么做作,但下面的例子足以给你一些基本的想法):
public enum Bestiary {
DOG(1) {
@Override
void makeNoise(Loudspeaker ls) {
ls.shoutOutLoud("I am alpha dog");
}
},
CAT(2) {
@Override
void makeNoise(Loudspeaker ls) {
ls.shoutOutLoud("I am beta cat");
}
},
RAT(3) {
List<String> foods = new ArrayList<>();
{
foods.add("gods");
foods.add("dogs");
foods.add("cats");
foods.add("other rats");
}
@Override
void makeNoise(Loudspeaker ls) {
StringBuilder cry = new StringBuilder("I am THE rat; usually I eat ");
for (int i = 0; i < foods.size(); i++) {
cry.append(foods.get(i));
if (i != (foods.size() - 1)) {
cry.append(", ");
}
}
ls.shoutOutLoud(cry.toString());
}
},
THE_THING(4) {
String name = "r2d2";
@Override
void makeNoise(Loudspeaker ls) {
ls.shoutOutLoud(calculateHash(name));
}
private String calculateHash(String smth) {
return String.valueOf(smth.hashCode());
}
};
private int id;
public int getId() {
return id;
}
Bestiary(int id) {
this.id = id;
}
abstract void makeNoise(Loudspeaker ls); // all enum elements will need to implement this - kind of like implementing an interface (which was also an option); note that we pass some arbitrary object and call methods on it
}
调用此类的代码可能如下所示:
public final class Loudspeaker {
private static Loudspeaker loudspeaker = new Loudspeaker();
public static void shoutOutLoud(String cry) {
System.out.println(cry);
}
static class Noizemakers {
public static void makeSomeNoise() {
for (Bestiary creature: Bestiary.values()) {
System.out.println(creature + " with id " + creature.getId() + " says: ");
creature.makeNoise(loudspeaker);
}
}
}
public static void main(String[] args) {
Noizemakers.makeSomeNoise();
Bestiary.CAT.makeNoise(loudspeaker);
}
}
在代码审查期间,我的建议被嘲笑为“太老套,利用枚举具有类主体和方法的事实,并且总体上具有不好的代码气味”。虽然将它转换成一个单独的接口,一堆普通的 Java 类等只是几分钟的事情,但我对这个解释不太满意。是否有任何指导方针说您应该像其他语言一样仅以其基本形式使用枚举?这种方法有什么真正的缺点? Joshua Bloch 关于将单例编写为枚举的建议怎么样?在这种情况下,这样的枚举必须是一个成熟的类,对吧?
【问题讨论】:
-
“利用枚举具有类主体和方法这一事实”?听起来您因使用新的(ish)语言功能而受到批评。他们是否也不喜欢使用泛型集合?
-
好吧,他们只是说“hackish”,我使用了其余的 :) IMO 使用标准语言功能没有 hack
-
@AlexeyDanilov 我认为 Java 泛型是以一种骇人听闻的方式实现的,因为需要完全向后兼容。当您尝试使用协变量做任何重要的事情同时仍然需要静态类型安全时,类型擦除的使用会让人很烦人,例如用具有通用返回类型的方法覆盖具有原始返回类型的方法(尽管相反是有效的,看起来)。并且在泛型类/方法中对对象的方法调用也存在问题。 (并不是说我尽可能不使用泛型;它们仍然比替代方案好很多。)
-
我同意泛型。它们不像其他语言中的类似结构那样方便处理,这些结构首先设计为类型安全。但是,是的,它们总比没有好,我们经常使用它们。
-
我不认为在方法中使用枚举有什么“hackish”。也就是说,我认为你的枚举会更清晰,如果它只是将噪音作为基类中的一个字段,每个值作为构造函数参数传入。现在每个值都有很多代码,这使得它们看起来都在做非常不同的事情。但这都是一样的,只是将一个常数值传递给 Loudspeaker。 IMO,这种简单性正在消失在噪音中。
标签: java design-patterns enums