枚举切换到处理接口方法调用.bad练习?

时间:2014-01-27 14:07:45

标签: java spring enums

我问了这个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

7 个答案:

答案 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模式,但这似乎有点矫枉过正。

看看:http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/Calendar.java#Calendar.getInstance%28java.util.Locale%29

他们在那里使用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