Win a copy of Learn Spring Security (video course) this week in the Spring forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

what to do about chained if-then-else?

 
Jim Bassy
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I am studying on how to use some design patterns in my latest project and I am having trouble with applying any of them. I am modifying existing code on my team and its just rife with if then else blocks. The problems is that clients send us messages, codes are attached to the message body and based on the code we do something with the message.
For example these are 3 variations of the same message that we can receive
Ex1
MT500
121z:GFSD|45TR|AB1

Ex2
MT500
121z:GFSD|45TR|B3

Ex3
MT500
121z:GFSD|45TR|AB2

The Mt500 message is the same except for the last code separated with a bar "AB1, B3 and AB2" are 3 different codes and they have meanings to perform some action. What was done was to create an enumeration of all Codes Mt500 can have and use chain if-then-else to decide on what to do. Lucky me the client added a new code called "CC4" that I have to add.

I'm trying to see how I can best do this in an OO way but i'm stuck. I was thinking of Java classes for each type of code but that doesn�t seem right. I looked at some of the solutions on the net for switch statements but they dont seem to apply. They seem to suggest the "thing" you are checking for should be an Object, like "if type == Cat then do something." To make matters worse you can have different combinations of these code. For instance
if((code.equals("AB1") || code.equals("B3"))
{
doSomething();
}
else if(code.equals("AB2")
{
doSomething2();

}

With new codes possibly being added it seems this if block will get a lot bigger. I will appreciate some direction on how I can do solve this. I could just add the new if condition and move on to some other task but I know there has to be a better way. Thanks.
 
Stevi Deter
Ranch Hand
Posts: 265
Hibernate Java Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Jim,

I'd highly recommend you take a look at Refactoring by Martin Fowler, et al., Refactoring Workbook by William C. Wake, and Refactoring to Patterns by Joshua Kerievsky. These three books will really help you understand the best approaches to take to modifying an existing code base, and how to take advantage of patterns and begin to see where to apply them in the process.

For example, in Refactoring Workbook, Wake suggests that several if statements or a switch statement that operate on the same field/code, such as your example, could represent Simulated Inheritance. He suggests you refactor the code to use subclasses or a state/strategy instead of the code.

The Workbook is especially useful as he gives the series of steps you should go through to minimize disruption and introduction of bugs as you refactor.

And welcome to the JavaRanch!
[ May 21, 2008: Message edited by: Stevi Deter ]
 
Jim Bassy
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok thanks. I took a quick peek at the description of the books on amazon it looks promising. I'm reading Head First Design Patterns right now. After doing some more research on the net it seems that I think I narrowed down where the state pattern and my problem lie. The State Pattern said the actions that cause the state to change should be method calls described as state transition actions. This is fine for when you know what method to call but in determine which method to call is where I'm stumped. The only way for state to change is from parsing a message file that can be variable, how does that fit into method delegation in the State class. If certain conditions are met in the file then state can change.

The following is a typical requirement spec for state transitions
if 89==DEAL && 5J==[JAMA|TOR|SINJA] - state=Rejected
 
Bear Bibeault
Author and ninkuma
Marshal
Pie
Posts: 64606
86
IntelliJ IDE Java jQuery Mac Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
"Jim",

There aren't many rules that you need to worry about here on the Ranch, but one that we take very seriously regards the use of proper names. Please take a look at the JavaRanch Naming Policy and adjust your display name to match it.

In particular, your display name must be a first and a last name separated by a space character, and must not be obviously fictitious.

Thanks!
bear
JavaRanch Sheriff
 
Andrew Laughlin
Greenhorn
Posts: 19
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Jim,

In the code above, could you elaborate on the doSomething() methods?

Andrew
 
Jim Bassy
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The dosomething() methods is nothing special. Based on the condition I just set the current state to Open, Rejected, etc. There are about 15 or so of these states.
 
Nicholas Jordan
Ranch Hand
Posts: 1282
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I have thought about what you are asking many times. Chained if/else resolves to a design pattern, I remember that ... but I forgot how I did it. Several notes do not forget though:
  • If you have 15 states, then one thing is changing the state - that's a variable.
  • If all fifteen states are to be recognized, then that information has to be somewhere.
  • Moving the resolution to method call names is limited in power.
  • Consider the problem of storing state as possibly yielding to a lookup table.
  • If that does not work, consider the collections.
  • Then, from memory, shortly after working on the last question I recover the overall approach. It is one that works.
     
    steve souza
    Ranch Hand
    Posts: 862
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    A couple different approaches you could take...



    1) A better solution than to have different method names for doSomething() would be to use doSomething() in all cases and put this method in a DoSomething interface. All of you objects must implement this interface. You could then have a static factory method that returned objects implementing this interface.





    2) A more flexible approach could be based on the DoSomething interface mentioned above. You could have a factory object that allows users to check implementations of your doSomething() interface.

    It would sort of work like a hashmap, however you would have to have a little more logic like a regexp as the key or perhaps even something of your own creation. The advantage of the first approach is you don't have to modify 'if' statements to add new DoSomething objects. Examples:



    3) If you must use different method names for some reason you could do an approach like the above, but put the method name in the factory and call it dynmaically. It really isn't a factory in this case, but would allow you to determine what methods execute on the fly. Something like this.

     
    Peter Hu
    Ranch Hand
    Posts: 33
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    For condition branchings, sometimes it can get very complex. Like the conditions may have haierachy structure that involves multiple objects. I just use a combination of possible values as keys -

    obj1-value1 + "|" + obj2-value1
    obj1-value1 + "|" + obj2-value2
    obj1-value1 + "|" + obj2-value3
    obj1-value2 + "|" + obj2-value1
    obj1-value2 + "|" + obj2-value2
    obj1-value3 + "|" + obj2-value3
    ....
    [ July 05, 2008: Message edited by: Peter Hu ]
     
    • Post Reply
    • Bookmark Topic Watch Topic
    • New Topic