Reputation: 4262
An enum structure declared in its own class is a member variable to the business logic class. That enum basically represents the state of that other class.
Although I have revisited the issue several times, replacing, or getting rid of those case statements proves quite frustrating to me.
Several business logic methods simple iterate over the enum and change the state of that class by assigning another value of the same enum, and other properties.
public enum MyEnum{ A,B,C,D }
The business logic class has this enum as a member:
public class BusinessLogic {
private MyEnum CurrentSelection;
private int propertyX;
private int propertyY;
public void operation1(){
switch(CurrentSelection){
case A: {alter propertyX this way; break;}
case B: {alter propertyY this way; break;}
case C: {alter propertyX that way; break;}
case D: {alter propertyY that way; break;}
}
}
public void operation2(){
switch(CurrentSelection){
case A: {CurrentSelection=MyEnum.B; break;}
case B: {CurrentSelection=MyEnum.C; break;}
....etc
}
}
public void operation3(){
switch(CurrentSelection){
case A: {CurrentSelection=MyEnum.D; break;}
case B: {CurrentSelection=MyEnum.A; break;}
....etc
}
}
}
Another client class will instantiate the business logic class, initialing its properties and then using its operation methods.
What I have successfully done (with help from SO) is encapsulate the operation methods into a command pattern structure so I can call the operations without any case statements. (here).
I guess my trouble is how to encapsulate the case statements in my business logic class. I suspect that I would need polymorphism and the appropriate data structures.
The refactoring experts suggest each case statement should be an implementation of a common interface. But if I have 3 methods iterating over a 4-member enum that means I'd probably need 3 interfaces with 4 implementations each, giving me 12 classes (plus 3 interfaces). Wouldn't that be a class overload? The logic is working fine with those 3 methods as they are, but the issue are the repeating switch/case statements.
Is there a way to refactor those switch statements but avoid a myriad of other classes in the name of polymorphism? Would it be possible to factor out the iterate-over-the-enum part? Or just the cases (where the logic is) should be refactored?
As a first step I removed those methods completely my having them implement a simple interface:
public interface Command {
void execute();
}
So, its operation method implemented the command interface:
public class Operation1 implements Command {
private void doOperation1(){
switch(CurrentSelection){
..all the cases here
}
}
public void execute() {
doOperation1();
}
}
As I see this, it will buy my a cleaner business logic class, but the trail of the switch cases will remain, right?
Upvotes: 1
Views: 2009
Reputation: 19131
As you may have guessed from the other responses, this is a common problem and has been codified into a refactoring by Martin Fowler. Take a look at the refactoring Replace Conditional with Polymorphism. There is also a similar codified refactoring by Joshua Kerievsky (Replace Conditional with Strategy).
Upvotes: 0
Reputation: 13114
To elaborate on my comment, and approach what I think rmn is talking about, you could do the following:
public interface MyInterface {
operation1(property);
operation2(property);
operation3(property);
}
public enum MyEnum implements MyInterface {
A {
operation1(property) {
//Do Stuff
}
operation2(property) {
//Do Stuff
}
operation3(property) {
//Do Stuff
}
},
B {
operation1(property) {
//Do Stuff
}
operation2(property) {
//Do Stuff
}
operation3(property) {
//Do Stuff
}
},
C {
operation1(property) {
//Do Stuff
}
operation2(property) {
//Do Stuff
}
operation3(property) {
//Do Stuff
}
},
D {
operation1(property) {
//Do Stuff
}
operation2(property) {
//Do Stuff
}
operation3(property) {
//Do Stuff
}
}
}
This makes it so that you have a command pattern - i.e. something that does the work for you based on the different element selected. It is also similar to a state pattern, although the focus here is on the execution rather than the data or the state of data.
Hope this helps.
Upvotes: 1
Reputation: 2426
you could include all three methods in an interface and have different implementations of that interface (one for each enum), and have this buisness class delegate the calls..
also for changing the state, have the return value from the operation be that common interface so that upon invoking these methods, the invoking class could return the appropriate object for the next state.
Upvotes: 1