I'd like to discuss possible alternatives to chained if-else statements when using OO language.
There are suggestions that instead of using if-else one should leverage on polymorphism. However, it seems that we still need a component that will run through the chained if-else in order to decide what to do.
Let's consider the following example.
In this example we create an object of User type. The actual object implementation depends on the parameter sent to the factory. There are four User implementations available to us: GoodUser, VeryGoodUser, BadUser and VeryBadUser
How does one avoid such if-else statements? What would you do?
Often HashMaps and database tables can get rid of ifs. When you think about it a HashMap "get" and an SQL point query are both ifs that return values (on difference is that they can't execute logic directly unlike a java if condition).
Below I get rid of the ifs by having the factory use a HashMap. Your user objects not implement a creational method called getInstance (you could also use an alternative approach and have the objects created via reflection).
An advantage of this approach is that other developers can check User objects into your factory.
Here is using reflection. I can't remember the method to user to get the class object, but then you would call newInstance on this. Obviously this is much easier to do, but you are exposing your class name, and the fact that you always are calling a public constructor.
I'd provide more details here, but I am late for work, and this forum doesn't pay may bills . Look up newInstance() and you will see how to do this. [ December 30, 2004: Message edited by: steve souza ]
Joined: May 15, 2002
Originally posted by steve souza: Often HashMaps and database tables can get rid of ifs.
Originally posted by Alex Sharkoff: How does one avoid such if-else statements? What would you do?
You could use a Map approach as already suggested, but that's just a slightly different way to present what actually is a table.
Question is, of course, why would you want to avoid the if-else chain?
The problem with type cases, as those switch/if "tables" are often called, is that they are often
- implemented at the wrong place, and/or - duplicated over the code,
thereby violating the Open Closed Principle. By introducing classes for the different cases, having only one central place where you decide which one to use, and using polymorphism at all the other places, you can dramatically reduce the number of changes needed to make when you introduce a new case.
Wether you use a Map or actually an if-else chain for that initial instanciation isn't that important at all. The goal shouldn't be to fully get rid of if statements, but to replace them by polymorphism where doing so increases the agility of the code!
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
Joined: Jul 11, 2001
Originally posted by Gerald Davis: Myth: OOP eliminates the "complexity" of "case" or "switch" statemen.
I don't know where that "myth" would be coming from, and it certainly is misleading. It's true, though, that wise use of polymorphism can replace some forms of so called "type cases" and thereby make code more maintainable and reusable.
Unfortunately, the whole article is full of more misunderstandings and myths - for example that Circle.draw() would be "OOPish", whereas Draw.circle() is "Procedural". That's simply not the case, as anyone should be aware of who knows Design Patterns such as Command and Visitor.
Also the argument about code length is absolutely besides the point. The reason for using OO (at least to me) is not to reduce the amount of code to write, but to make the code easier to maintain and extend. And I'm quite certain that I can use OO in a way that does this for me.
[rant]I know the author of the article from some discussions at the usenet, and my feeling is that he simply didn't care to give OOP enough of a try to learn how to use it to his advantage. I'm OK with that - there is only so much you can learn, and you have to take priorities. I am, for example, quite ignorant of functional (not procedural!) programming. But I also don't write strange articles about the disadvantages of functional programming, because I fear they would be as much beside the point as I find those anti-OO articles are... <sigh>[/rant]
Joined: Jun 26, 2002
Wether you use a Map or actually an if-else chain for that initial instanciation isn't that important at all.
I disagree. The if condition logic doesn't allow you to add new User types to the factory whereas the Map approach does. This type of coding is crucial when writing framework code that others will reuse. [ December 30, 2004: Message edited by: steve souza ]
Absolutely, Steve. One of my requirements in 2004 was to implement a stable core that could plug in new product lines without modification. The core delegates lots of work to strategies that are retrieved from a map based on some key fields in the input. An application assembler object reads configuration - any number of XML files in a given directory - and loads up the map.
The prior generation of our system had many long if/else chains. Every time we added a product line we added another else. Every time we opened code we risked breaking it. And with if/else it was tempting to put all the guts of the logic right in line and overnight we had 500 line methods. The strategies force at least a bit of modularity.
I agree with Ilja (never a bad thing to do, I find) that the pages under that tablizer site are mostly too confused to even respond to.
A good question is never answered. It is not a bolt to be tightened into place but a seed to be planted and to bear more seed toward the hope of greening the landscape of the idea. John Ciardi
Joined: Jul 11, 2001
Originally posted by steve souza:
I disagree. The if condition logic doesn't allow you to add new User types to the factory whereas the Map approach does. This type of coding is crucial when writing framework code that others will reuse.
But often enough you don't write a framework, at least not from the beginning. Often enough you simply know that the set of choices is written in stone for the near future, that you don't need to configure it at runtime. Then a Map might well already be overkill, especially for a small number of choices (for a bigger number of choices, I often find the Map approach to be more readable).
And once you find out that you actually *need* to configure the mapping at runtime, it's not hard at all to refactor to a Map solution - *if* you designed it so that you only have to touch one place.
It strikes me that to some extent, this particular example may be somewhat missing the point of the whole if-statements-are-evil argument. In the case of a factory like this, yes, you can clean things up a bit with a map or whatever, but that's a different problem then something like this:
Here, you'd generally much rather see something like:
...where you're taking advantage of polymorphism to get an object of some unknown type to do its type-specific thing.
Co-Author of <a href="http://www.oreilly.com/catalog/jswing2" target="_blank" rel="nofollow">Java Swing</a><br />Co-Creator of <a href="http://www.sun.com/training/catalog/courses/CX-310-055.xml" target="_blank" rel="nofollow">SCJP 5.0</a> and <a href="http://www.sun.com/training/certification/java/associate_beta.xml" target="_blank" rel="nofollow">SCJA</a> exams
Joined: Jul 11, 2001
Good point, Dave!
And if you don't want to put doYourThing into the Shape interface, you could use the Visitor pattern: