我有这些假设通过时间来成长值枚举类,我想谁添加新的枚举值也提供impementation地方的用户。但我不知道如何迫使他们提供impementation为impementation会在其它的类。对于如
public enum DayType {
SUNDAY,
MONDAY;
}
提到在一类
class X{
DateType dateType;
..
}
而在一些其他类中使用
if (x.getDateType().equals(DayType.SUNDAY)) {
...
}else if(x.getDateType().equals(DayType.MONDAY)){
..
}
所以,如果有人添加日期时间那么他应该被强迫在上面的if-else逻辑添加实施为好。优选通过加入如果可能的话功能接口?
我不能强迫执行枚举类作为实施有弹性的依赖。
真正的答案是:不这样做。
如果你有一些“类型”,而你知道,这个“型”可以看到随着时间的推移新的变身,需要不同的行为,那么答案就是使用抽象类和多态性。
这不要紧,如果你使用的if / else链,或switch语句:你有类似的想法:
if (someObject.getSomething() == whatever) { then do this } else { that }
是不好的做法!
如果在所有的,你应该使用这样的switch语句在工厂内返回不同的子类的实例,以然后调用这样的对象“共同”的方法。
您目前的做法是:a)关于内部状态和B)以多种方式还强制依赖外化的知识。
这是意大利面条代码是如何开始!更退一步,想想解决这个更面向对象的方式!
虽然我怀疑这可能在编译时会受到限制。一个可能的更清洁的方式来实现类似的东西会使用switch
这里:
switch (x.getDateType()) {
case MONDAY: // do something
break;
case SUNDAY: // do something
break;
default:
throw new CustomException("No implementations yet for :" + x.getDateType());
}
对空指针的选择另一种方法是把这种逻辑在枚举本身,假设这使得在您的设计感(如果可以的责任与天枚举类型撒谎)。
public enum DayType {
SUNDAY {
@Override
void processSomeAction(Object input) {
super.processSomeAction(input);
// process action with SUNDAY-specific logic
}
},
MONDAY;
//can be made abstract if there's no default implementation
void processSomeAction(Object input) {
// process action with default logic
}
}
这将确保提供具体日期的实现的需要是显而易见的开发谁更改DayType
。
而来电者将只需要:
x.getDateType().processSomeAction(inputIfApplicable);
您可以创建一个界面,将你的枚举类实现。在这种情况下,所有的枚举在接口来实现方法。
public enum DateType implements DateTypeInterface {
SUNDAY {
@Override
public void checkCondition() {
System.out.println("Implement Sunday logic");
}
},
MONDAY {
@Override
public void checkCondition() {
System.out.println("Implement Monday logic.");
}
}
}
public interface DateTypeInterface {
public void checkCondition();
}
我不认为你必须在编译时的选项来执行你的政策。我的建议是创建一个单一的方法(比如DateTypeAction
),然后产生基于您action()
的数值(有点类似于DateType
)具体实现的工厂的接口(类似DateTypeActionFactory.getDateTypeAction(DateType dateType)
)。在你的初始化阶段,你可以通过你的DateType(DateType.values()
)的所有值运行,并检查是否有您的DateTypeAction
每个值非空执行DateTypeActionFactory
的。如果找到了一个或多个值丢失实现抛出具有明确的错误信息,告诉实现(S)为/缺失,但无法启动您的应用程序的一个例外。这似乎是一个合理的模式。
顺便说一句,如果你用这种模式去,我有个建议:我写了名为MgntUtils一个开源的Java库,它提供了一个简单的框架(非常适合使用Spring)具有自我填充工厂模式。即你可以创建一个接口和扩展库提供的父类,然后你的界面的每一次实施一个工厂将被自动插入到你的工厂预先定义的名称。我用了很多次,发现它十分便利。这里是链接到描述整个图书馆的文章:MgntUtils Open Source Java library with stack trace filtering, Silent String parsing, Unicode converter and Version comparison。寻找段落
生命周期管理(自实例化厂)
对于该功能的简短说明。在这里,你可以阅读有关该功能的整个想法:Non-intrusive access to "Orphaned" Beans in Spring framework。这两篇文章解释从哪里得到图书馆为好,但这里是直接链接:Maven Central Repository和Github。该库提供写得很好的javadoc
枚举是为了保持编译时(静态)终值,以便动态地添加更多的值是不可能的(只是把它那里)。至于你的问题的另一部分,如@nullpointer指出,最好是使用switch
条款。除了改进代码的清晰度,编译器警告说,如果有没有宣布对他们(也就是给你忽略case
)default
声明枚举值
我也不能肯定是否延期由用户设计枚举是一个好主意。这是静态的,如@Garikai说。这将导致代码味道。
如果你想有容易的选择从枚举扩展映射的功能我建议Map<DateType, Function> map = new EnumMap<DateType, Function>(DateType.class);
然后用getOrDefault
保证你会得到任何输出。
这个答案扩展了一些其他的答案在这里推广使用多态的。
我通常会尽量做到避免的每增长的开关/有条件的地方,就是一个识别方法添加到接口:
public enum Day {
SUNDAY, MONDAY
}
public interface DayProcessor {
Day day();
// I don't know what Days are supposed to do exactly
Object process(Object input);
}
然后,我创建了所有由Spring有线在可用DayProcessor
实现的工厂组件:
@Component
public class DayProcessorFactory {
@Autowired
private List<DayProcessor> dayProcessors;
public DayProcessor create(Day day) {
for (DayProcessor dayProcessor: dayProcessors) {
if (dayProcessor.day().equals(day)) {
return dayProcessor;
}
}
// DayNotFoundException extends RuntimeException
throw new DayNotFoundException(String.format("No DayProcessor found for day %s", day));
}
}
这是Strategy Pattern的一种形式。
另一种方法,列出所有的日子是通过枚举他们(但你不得不更新列表时,新的一天被创建):
private DayProcessor[] dayProcessors = new DayProcessor[] {new MondayProcessor(), new SundayProcessor()};