Java Best Practices – Is It Good to Burn Business Logic into Enums?

business-logicenumjava

Let's have a simplified business logic like this:

public enum BusinessLogic {
   STAGE_ONE(true, false, false),
   STAGE_TWO(true, true, false),
   STAGE_THREE(false, false, true);

  private final Boolean canStartProcessing; 
  private final Boolean canDoStuff; 
  private final Boolean canFinish;

  private BusinessLogic(Boolean canStartProcessing, Boolean canDoStuff, Boolean canFinish){
     ... usual simple constructor
  }
  ... getters
}

And let's say it is mapped to my Business Object like this:

public class BusinessObject {
  ... constructors, fields, getters, setters, etc...

  private BusinessLogic logic

  @Enumerated(EnumType.STRING)
  @Column(name = "LOGIC")
  public BusinessLogic getLogic(){...usual getter...} 

  public BusinessLogic setLogic(){...usual setter...}
}

When the workflow arrives for example Stage two, the BusinessObject will be updated and LOGIC field should be set to BusinessLogic.STAGE_TWO, therefore you can use functions like "start process" and "do stuff", before that you can't "do stuff", altough when it reached stage three, you can't do anything else, but "finish" the process.

Does this kind of business logic structure has something to do against good practice?
I mean for example: maintainability, not fully represented in Database or anything else I didn't think of?

Best Answer

I use enums this way all the time. Enums are a great way to write immutable helper objects that you only need exactly one copy of; they help reduce the chance of memory leaks and easily group many related classes together in a clear way.

What I would not do is expose the control of which particular BusinessLogic you're using to external classes using a public getter and setter method; that is violating encapsulation.

It looks like your use case uses the State Pattern, which is a great use for enums in Java. However, by removing the state transition logic from the class, you can't guarantee that other code will change the state when you don't expect. Fix this by having the state transition code inside the BusinessObject class itself, or at least in a package private object that you inject into the BusinessObject class.