使用setter将服务注入Enum ......糟糕的做法?

时间:2014-01-27 02:23:46

标签: java spring enums

这被认为是不好的做法吗?本质上,基于枚举我想在接口中调用特定方法。每个枚举都有自己的接口实现(WalkImpl,RunImpl,JogIMpl等),所有这些都基于ActivityService接口。我只是想知道这是将服务“注入”Enum的正确方法。我这样做是因为我无法自动提供服务。谢谢

@Component
public class HelloWorldImpl implements HelloWorld {

private enum MyEnum{

    WALK {
        @Override
         public void execute() {
            System.out.println("I am walking");
            activityService.doSomethingWithMe(this.name());
        }
    },
    RUN{
        @Override
        public void execute() {
            System.out.println("I am running");
        }
    },JOG{
        @Override
        public void execute() {
            System.out.println("I am jogging!");
        }
    }, SKIP{
        @Override
        public void execute() {
            System.out.println("I am skipping!");
        }
    };

    public abstract void execute();

    private static ActivityService activityService;

    public void setActivityService(ActivityService activityService) {
        this.activityService = activityService;
    }
}


@Autowired
ActivityService activityService;


 @Override
 public void executeMe(){
    MyEnum myEnum = MyEnum.WALK;
    myEnum.setActivityService(activityService);
    myEnum.execute();

  }
}

2 个答案:

答案 0 :(得分:5)

不要使用这样的枚举。当我有更多的时间我将解释,但大多数程序员期望甚至Java语言有点期望枚举是幂等的和不可变的。

枚举中的所有成员变量都应该是final,枚举不应该产生副作用。这是因为枚举是函数式编程风格调度的一种形式(尽管很糟糕)。这应该被视为符号而不是对象(即使它们是单例对象)。

除非您遵循上述功能规则,否则不要使用枚举来解决单例模式。以下是我对你给定代码的理解:

@Component
public class HelloWorldImpl implements HelloWorld {

    private enum MyEnum{
        //Notice the final here 
        private final String message;
        WALK ("I am walking"),
        RUN("I am running"),
        JOG("I am jogging!"),
        SKIP("I am skipping!");

        public MyEnum(String message) { this.message = message; }

        public String getMessage() { return this.message; }

    }        

    @Autowired
    ActivityService activityService;

    @Override
    public void executeMe() {
       MyEnum myEnum = MyEnum.WALK;
       _executeMe(myEnum);
    }

    void _executeMe(MyEnum m) {
        //switch or if on the enums you want to 
        //do stuff on with the activity service.
        System.out.println(m.getMessage());
        if (m == MyEnum.WALK)
           activityService.doSomethingWithMe(m.name());
    }
}

答案 1 :(得分:4)

枚举最适合用于必须在代码中区分的事物 - 业务逻辑。如果你使用它们作为数据(作为你的例子),它对我没有任何意义。

此外,通过数据与代码,我不是简单地迭代它们,你实际上必须使用不同的枚举使用明显不同的代码,否则它们只是一个(坏的)数据初始化设备。

更好地初始化该类型的数据可能是:

String[] init=new String[] {"WALK", "I am walking", "SKIP", "I am skipping", ...}
Map lookup=new HashMap();
for(int i=0;i+=2;i<init.length)
{
    lookup.put(init[i],init[i+1])
}

没有冗余,更简单,当列表变得更复杂时,将它从代码中移到文本,属性,xml或您喜欢的任何数据类型上都是微不足道的。

你甚至可以通过包装&#34; Lookup&#34;这整个初始化为一个对象(一个好主意)我做了一些看起来像这样的东西:

public class Motivate() 
{

    private static Map<String, Motivate> motivations;
    private String action;
    private String description;

    private Motivate(String action, String description)
    {
        this.action=action;
        this.description=description;
    }
    public void init()
    {
        if(motivations == null)
        {
            build motivations using all the stuff in the first example
        }
    }
}

如果您想要附加不同的代码(假设您的示例只是微不足道,并且每个&#34;模式&#34;需要不同的代码),请添加一个包含&#34; Runnable&#34;等界面的成员。并在构建它们时将其传递给构造函数。

那么你的代码永远不应该引用&#34; RUN&#34;或&#34; WALK&#34;,它只是绑定到用户按键或其他数据的数据。