简体   繁体   English

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

[英]using setter to inject service into Enum…Bad Practice?

Is this considered bad practice? 这被认为是不好的做法吗? Essentially, based on the enum I want to call a specific method in an interface. 本质上,基于枚举我想在接口中调用特定方法。 Each enum will have its own interface implementation (WalkImpl,RunImpl,JogIMpl, etc....) all based off of the ActivityService interface. 每个枚举都有自己的接口实现(WalkImpl,RunImpl,JogIMpl等),所有这些都基于ActivityService接口。 I just wanted to know is this the right way to "inject" a service into an Enum. 我只是想知道这是将服务“注入”Enum的正确方法。 I am doing it this way since I can't autowire the service. 我这样做是因为我无法自动提供服务。 Thanks 谢谢

@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();

  }
}

Do not use enums like that. 不要使用这样的枚举。 When I have more time I will explain but most programmers expect and even Java the language somewhat expects enums to be idempotent and immutable. 当我有更多的时间我将解释,但大多数程序员期望甚至Java语言有点期望枚举是幂等的和不可变的。

All member variables in an enum should be final and an enum should not produce side effects. 枚举中的所有成员变量都应该是final,枚举不应该产生副作用。 This is because enums are a form (albeit crappy) of functional programming style dispatch. 这是因为枚举是函数式编程风格调度的一种形式(尽管很糟糕)。 That is enums should be treated as symbols and not objects (even though they are singleton objects). 这应该被视为符号而不是对象(即使它们是单例对象)。

Also do not use enums to solve the singleton pattern unless you are following the functional rules from above. 除非您遵循上面的功能规则,否则不要使用枚举来解决单例模式。 Here is how I would probably right your given code: 以下是我可能会对您的代码进行修改:

@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());
    }
}

Enums are best used for things that MUST be differentiated in code--business logic. 枚举最适合用于必须在代码中区分的事物 - 业务逻辑。 If you are using them for data (as your example), it doesn't make any sense to me. 如果您将它们用于数据(作为示例),对我来说没有任何意义。

Also, by data vs code I'm not talking about simply iterating over them, you actually have to have significantly different code USING different enums, otherwise they are just a (bad) data initialization device. 此外,通过数据与代码我不是简单地迭代它们,你实际上必须使用不同的枚举使用明显不同的代码,否则它们只是一个(坏的)数据初始化设备。

A better initialization of that type of data might be: 更好地初始化该类型的数据可能是:

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])
}

No redundancy, much simpler, and when that list becomes more complicated it's trivial to take it outside of the code to a text, properties, xml or whatever flavor of data you prefer. 没有冗余,简单得多,当列表变得更复杂时,将它放在代码之外的文本,属性,xml或您喜欢的任何数据风格都是微不足道的。

You can even associate code with these if that is what you are after by wrapping "Lookup" and this entire initialization into an object (A good idea) I'd make something that looked like this: 你甚至可以通过将“查找”和整个初始化包装到一个对象中来将代码与这些代码相关联(这是一个好主意)我会做出如下所示的内容:

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
        }
    }
}

If you want different code attached (assuming your examples were just trivial and each "Mode" needed different code), add a member that holds an interface like "Runnable" and pass that into the constructor when you build them. 如果你想要附加不同的代码(假设你的例子很简单,每个“模式”需要不同的代码),添加一个包含“Runnable”之类的接口的成员,并在构建它时将其传递给构造函数。

Then your code should never refer to "RUN" or "WALK", it is just data that is bound, for instance, to a users keystroke or some other data. 那么你的代码永远不应该引用“RUN”或“WALK”,它只是绑定到例如用户击键或其他数据的数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM