This week's giveaway is in the Android forum.
We're giving away four copies of Android Security Essentials Live Lessons and have Godfrey Nolan on-line!
See this thread for details.
The moose likes Java in General and the fly likes Avoid clumsy 'if' statements but avoid reflection too. Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Android Security Essentials Live Lessons this week in the Android forum!
JavaRanch » Java Forums » Java » Java in General
Bookmark "Avoid clumsy Watch "Avoid clumsy New topic
Author

Avoid clumsy 'if' statements but avoid reflection too.

James Bowen
Greenhorn

Joined: Jan 06, 2003
Posts: 1
Hi, I was looking for a way to handle business rules according to a char. I.e. if I receive char 'x' fire Business rule 1, if I receive char 'y' fire Business rule 2, etc.
I thought that an 'if' statement would be hard to maintain if new rules came along, and I thought reflection to generate a rule object based on the char might be overkill.
Is there a way of mapping business rules to a simple char without making a hard to maintain 'if' statement or expensive reflection?

Intuition tells me there's a factory pattern solution somewhere, but I can't work it out for sure!
Anyone have any ideas?
Thanks,
James
Marilyn de Queiroz
Sheriff

Joined: Jul 22, 2000
Posts: 9044
    
  10
If I only had 2 rules, I think I would use the if/else construct. Otherwise I would probably look for a way to use polymorphism.


JavaBeginnersFaq
"Yesterday is history, tomorrow is a mystery, and today is a gift; that's why they call it the present." Eleanor Roosevelt
Michael Ernest
High Plains Drifter
Sheriff

Joined: Oct 25, 2000
Posts: 7292

The next primitive step up is a case statement. It's an honorable tool; even when they grow, at worst they're tedious to read.
You could pass each character as an event object, rather than a primitive, and treat your business rules as event listeners. You can arrange it so that the business rule 1 object is only interested in 'a' events, etc., etc.
And there are some more complex approaches, such as a combination of Interpreter and Command design patterns (see this book) which would make sense if you anticipated a large-scale association here.


Make visible what, without you, might perhaps never have been seen.
- Robert Bresson
Blake Minghelli
Ranch Hand

Joined: Sep 13, 2002
Posts: 331
Here's something I've done on more than one occassion and had very good success. Personally, I think it is a good OO approach and it definitely avoids using an ugly "if/else" structure.
1. Create a "RuleHandler" interface or abstract class that defines a method to handle the rule processing, e.g. process(), handle(), validate() or whatever. Most likely, the method will have to take as a parameter some kind of object that encapsulates the data that needs to be validated. Also, you may want to throw a custom "RuleViolationException" that can describe what went wrong.
2. Then create a class that implements/extends RuleHandler for each business rule you have. Each subclass will provide the specific implementation of handling a business rule.
3. So how do you dynamically use the right RuleHandler depending on your char? Create the mapping in a properties file. I prefer XML but you can also use a standard properties (my.key=value). For example the XML props file would look like this:
...
<RuleHandler>
<!-- The ID (char) for your rule -->
<RuleID>x</RuleID>
<!-- A class that implements/extends RuleHandler -->
<RuleHandlerClass>XRule</RuleHandlerClass>
</RuleHandler>
<RuleHandler>
<RuleID>y</RuleID>
<RuleHandlerClass>YRule</RuleHandlerClass>
</RuleHandler>
...
4. Then dynamically getting an instance of your rule handler and processing the rule is easy:

Of course, I'm open to any criticism on this approach. Good luck!


Blake Minghelli<br />SCWCD<br /> <br />"I'd put a quote here but I'm a non-conformist"
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
You can convert the run-time reflection into initialisation-time reflection by using a Map which maps handlerNames to RuleHandler instances. That should address any performance concerns you might have.
In the original problem, the approach can be simpler and faster still, as you can probably convert the char to an integer index into a RuleHandler[] array.
The simplest approach would be to use a properties configuration file of the formEtcetera. This can be loaded up in a java.util.Properties object. At initialisation time,Will initialise the array of business rule handlers (the character 'A' corresponding to the zeroth element).
- Peter
[ January 06, 2003: Message edited by: Peter den Haan ]
Michael Ernest
High Plains Drifter
Sheriff

Joined: Oct 25, 2000
Posts: 7292

I had thought of a hashtable too, but never having used the approach myself I didn't mention it. Have you used this approach, Peter?
I've been getting wary myself of using properties for this kind of work, since it a) implies a start/restart routine to bring in changes, and b) leaves a proper restart in the hands of correct editing. My recent work with a lot of Sun ONE products in particular makes me wonder if XML-everything for config files is such a cool idea.
Blake Minghelli
Ranch Hand

Joined: Sep 13, 2002
Posts: 331
I've been getting wary myself of using properties for this kind of work, since it a) implies a start/restart routine to bring in changes, and b) leaves a proper restart in the hands of correct editing. My recent work with a lot of Sun ONE products in particular makes me wonder if XML-everything for config files is such a cool idea.

Storing the RuleHandlers in a map still requires that the map is populated somehow, most likely during initialization, so that by itself does not get you away from needing a restart to load new RuleHandlers.
If you don't want to restart in order to change handlers then you could consider replacing the properties lookup with a db lookup, or implement an "auto-refreshing" properties object.
However, that would still leave you with your concern about improper editing... I guess that depends on your deployment methodology. We always deploy to a test environment first, that way if there are any config errors (e.g. spelling error in a properties file or a db record), they'll be caught before moving to production.
Using XML for a config file is a matter of preference. At first I didn't like the idea, but the more I learned about it, it became very comfortable for me. We still use a lot of regular props files too!
Bottom line - make it as configurable as possible and stay away from hard-coding your rule handling.
That's my opinion for what it's worth!
Thomas Paul
mister krabs
Ranch Hand

Joined: May 05, 2000
Posts: 13974
Start/restart is really only a problem for long running processes such as servlets. Assuming that this is part of some batch process, you don't have to worry about reloading the handler array. If it is part of a servlet/jsp application then reloading is an issue. Make the handler array static (it should probably be anyway) and then write a servlet to run a reload method against the handler array. Whenever you create a new rule or update an old rule, you run the reload servlet and your handler array is up to date.


Associate Instructor - Hofstra University
Amazon Top 750 reviewer - Blog - Unresolved References - Book Review Blog
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
Originally posted by Michael Ernest:
I had thought of a hashtable too, but never having used the approach myself I didn't mention it. Have you used this approach, Peter?
Yes. The Charity Technology Trust raffle engine (see eg the current Royal British Legion raffle) uses a similar approach to define validation rules for various card types. As you don't see new types every day or even every year, the problems you rightly describe aren't very important in this case.
- Peter
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
Originally posted by Blake Minghelli:
If you don't want to restart in order to change handlers then you could consider [...] an "auto-refreshing" properties object.
However, that would still leave you with your concern about improper editing...
For our in-house controller, we implemented an auto-refresh by checking the configuration file timestamp every X seconds. This will read the new file and parse it into a new Configuration object. If an exception is thrown during the parsing and validation phase, this is logged and the new Configuration is discarded, leaving the old, working, configuration in its place. Only when the new configuration is valid it is actually installed.
This solves not only the restart problem, but also the editing problem. Not if you're editing the config file while the system is down, of course, but if you've taken the system down for maintenance anyway the editing problem isn't much of a problem in the first place.
You could do the same thing here. Just replace the old handler[] array only if you could successfully create the new one, including all object instantiations.
- Peter
[ January 06, 2003: Message edited by: Peter den Haan ]
Michael Ernest
High Plains Drifter
Sheriff

Joined: Oct 25, 2000
Posts: 7292

Thanks Peter!
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by James Bowen:
I thought that an 'if' statement would be hard to maintain if new rules came along,

Do you feel the same about the switch-statement proposed above? If so, why?
I think for rather static situations (rules don't come along very often and it would be okay to change the source code in that cases), the switch solution would be quite ok. If your requirements are more dynamic, you will need one of the more complex solutions, of course.


The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
 
 
subject: Avoid clumsy 'if' statements but avoid reflection too.
 
Similar Threads
JBoss Rules Doubts
Business Rules & Jython
asking the best next question to have as many rules fire as possible
Looping though get methods without using reflection
[AspectJ] Jess idea from where?