我问了这个question,但我想也许这应该是一个单独的问题。鉴于以下课程。这是基于枚举类型处理特定于接口的方法调用的最佳方法吗?感谢
@Component
public class HelloWorldImpl implements HelloWorld {
private enum MyEnum{
WALK,RUN,JOG,SKIP
}
@Autowired
@Qualifier("walkService")
private ActivityService walkService;
@Autowired
@Qualifier("runService")
private ActivityService runService;
@Override
public void executeMe(){
MyEnum myEnum = MyEnum.WALK;
for(MyEnum enum : MyEnum.values()){
switch(enum){
case RUN:
runService.execute();
case WALK :
walkService.execute();
etc....
}
}
}
}
我试图确定是否有一种方法可以使用接口(即ActivityService)来调用execute方法而不是特定于“MODE”(即switch / if)。我只是想着如果我添加一个新的“MODE”会发生什么,我将不得不记住在这个switch语句中添加一个部分。任何帮助是极大的赞赏。
*更新 建议使用此确切模式here。
答案 0 :(得分:2)
你最好为enum本身添加一个方法:
private enum MyEnum {
WALK {
@Override
public void execute() {
...
}
},
RUN {
@Override
public void execute() {
...
}
}
public abstract void execute();
}
那样,那里(如果没有实现其关联的execute()
方法,你就无法添加新的枚举值。
方法变为:
public void executeMe(){
MyEnum myEnum = MyEnum.WALK;
myEnum.execute();
}
答案 1 :(得分:2)
我怀疑你能不能做得更好。好吧,你可以使用Factory模式,但这似乎有点矫枉过正。
他们在那里使用If语句。好像你的代码更好。
In order to evolve code in a factory scenario :
a) Caller has to know something about the "kind" of concrete implementation needed
b) For each "kind" of service a subclass is needed
也许在你的实现中唯一批评的是“kind”被HelloWorldImpl隐藏,它“知道”要返回哪个服务。它可能更直接地使用子类,因为方法“executeMe”没有说明在运行时将选择什么类型的服务(它取决于枚举)。
答案 2 :(得分:1)
您不需要这样的switch
声明:)
@Override
public void executeMe(){
runService.execute();
}
您只需要在界面上调用方法即可。 JVM将运行已分配给service
变量的任何实现。这就是接口之美以及它们存在的确切原因。
答案 3 :(得分:1)
定义enumKey =>的映射concreteActivityServiceBean; 在你的春季应用程序环境中这样的事情:
<util:map id="activityServiceMapping" key-type="java.lang.String" value-type="com.somePackage.ActivityService" map-class="java.util.HashMap">
<entry key="RUN" value-ref="runServiceImpl" />
<entry key="WALK" value-ref="walkServiceImpl" />
</util:map>
@Component("runServiceImpl")
class RunServiceImpl implements ActivityService {
@Override
public void execute(){ ... }
}
@Component("walkServiceImpl")
class WalkServiceImpl implements ActivityService {
@Override
public void execute(){ ... }
}
并有条件地选择要执行的实现:
@Component
class HelloWorldImpl implements HelloWorld {
@Resource(name = "activityServiceMapping")
private Map<String, ActivityService> activityServices;
@Override
public void executeMe() {
ActivityService activityService = activityServices.get("WALK"); // or "RUN" or use the ENUM values....
activityService.execute();
}
}
答案 4 :(得分:0)
我认为你应该尝试重构你的类,所以你只需要一个ActivityService
类的实例。您的代码看起来像这样:
@Component
public class HelloWorldImpl implements HelloWorld {
private enum MyEnum{
WALK,RUN,JOG,SKIP
}
@Autowired
private ActivityService activityService;
@Override
public void executeMe(){
MyEnum myEnum = MyEnum.WALK;
activityService.execute(myEnum);
}
}
但如果不了解ActivityService
的责任,很难说这是否是一个可行的选择。
答案 5 :(得分:0)
或者,如果您真的只希望每次都使用正确的类型执行运行程序类而不使用DI或任何类选择代码或ifs或switch,那么请确保在执行之前实例化正确的类。
ActionExecutor actionExecutor = (ActionExecutor)Class.forName("com.package.name." + action.name()).newInstance();
actionExecutor.execute();
瞧!只要您为每个可能的操作都有一个类并且这些类具有默认构造函数,问题就解决了。
答案 6 :(得分:0)
我也遇到过类似的问题。我找到了比接受的答案更通用的解决方案。
第一步是创建一个接口。
public interface ActivityExecutor {
public void execute();
}
现在,所有必须执行的类都必须实现该类
public class WalkExecutor implements ActivityExecutor {
@Autowired
private WalkService walkService;
public void execute(){
walkService.execute();
}
}
public class RunExecutor implements ActivityExecutor {
@Autowired
private RunService runService;
public void execute(){
runService.execute();
}
}
现在以下列方式声明枚举
private enum MyEnum {
WALK {
@Override
public String getClassName() {
return "com.basepackage.WalkExecutor";
}
},
RUN {
@Override
public String getClassName() {
return "com.basepackage.RunExecutor";
}
}
public abstract String getClassName();
}
在处理部分中,执行以下操作。
String className = MyEnum.WALK.getClassName();
Class<?> clazz = Class.forName(className);
private static ApplicationContext appContext;
ActivityExecutor activityExecutor = (ActivityExecutor) appContext.getBean(clazz);
activityExecutor.execute(); // executes the required Service