Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using setter to inject service into Enum...Bad Practice?

Tags:

java

enums

spring

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. I just wanted to know is this the right way to "inject" a service into an 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();

  }
}
like image 885
Trevor Avatar asked Jan 27 '14 02:01

Trevor


People also ask

Can an enum have a setter?

Update: It's possible to have setters in enum types.

Can we use @value in enum?

No, it's not. The purpose for an Enum is to give us mapped data (fixed set of values) with limited scope. If we would to use @Value in Java enums, it would take the purpose of the enum away in the first place.

Can you inject an enum?

A perfectly functional method of injecting enum values in CDI. You will, however, need to make sure you know which type of enum you want to inject, and if you need multiple types, then you'll need to create qualifiers for each value.

Should enum fields be final?

The members of the enum are constants, but the reference variable referring to enum values is just like any other reference variable, hence the need to mark them as final .

How to inject dependency by setter method in Java?

We can inject the dependency by setter method also. The <property> subelement of <bean> is used for setter injection. Here we are going to inject Let's see the simple example to inject primitive and string-based values by setter method.

What is setter injection?

Setter injection is a dependency injection in which the spring framework injects the dependency object using the setter method. The call first goes to no argument constructor and then to the setter method.

What are the best practices for using enums?

Best Practice #1: Use enums to eliminate “magic numbers” from your code. Make your code explicit and easy to read. Pitfall #1: Using “magic numbers” leads to hard-to-understand code and business logic errors. Enums will eliminate these issues. The number behind enums is usually not important.

Why can’t I cast an integer to an enum?

The C# enum’s relationship to the integer type can lead to some strange behavior and code. You can’t implicitly cast an integer value to an enum. In other words, if a method requires you to pass in an EmployeeType when calling it, you can’t pass a “1” into the method to signify a Salaried employee.


2 Answers

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.

All member variables in an enum should be final and an enum should not produce side effects. 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());
    }
}
like image 173
Adam Gent Avatar answered Oct 18 '22 19:10

Adam Gent


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.

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.

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.

like image 4
Bill K Avatar answered Oct 18 '22 18:10

Bill K