This week's book giveaway is in the OO, Patterns, UML and Refactoring forum. We're giving away four copies of Refactoring for Software Design Smells: Managing Technical Debt and have Girish Suryanarayana, Ganesh Samarthyam & Tushar Sharma on-line! See this thread for details.
I have a stored procedure which returns results for a person's orders. I also have an object in my package called Order. This object contains general information about all types of orders. Order is then extended to OrderA, OrderB, etc where OrderA and OrderB each have the common base of Order but have different characteristics. The stored procedure returns the list of orders that meet the user's criteria. If the order is of type OrderA, I need 2 more pieces of data than for all other types of orders. These two columns are in the resultset. I am storing all of the common data to an Order object. After retrieving all information about the Order, I add the Order to the Vector. If the Order has these two extra pieces of data, it needs to be created as an OrderA, not an Order. I then need to add it to the Vector. I know that it is not good OO, but I am trying to add two different types of objects to the Vector. Both types are of type Order, one is more specific as OrderA. However, I cannot get this to work. I need to store the objects in the same Vector because the position of the orders is important when displaying the values in the JSP. I meant to use the operator instanceof when retrieving the values from the Vector in the JSP before displaying them, but I don't think that it even makes it back to the JSP when I call the method to retrieve these values. What is the recommended way of dealing with this situation? I have a collection of objects, some objects are a child of the other object. The only idea I have right now is to add these two special characteristics to the base object Order, even though they are only needed in OrderA, not in OrderB, etc. I know that this is bad OO, but I don't know how else to achieve the desired result of having all orders in the same Vector with all the information that is returned from the stored procedure. Your comments are greatly appreciated. Thank you.
I meant to use the operator instanceof when retrieving the values ...
Why won't the instanceof operator work? It seems that your original idea to subclass the different order types is a better design than adding dead state to a base class. If an Order object can be retrieved from the Vector, then instanceof should reveal its immediate class and then casting to that subclass can safely take place.
Any intelligent fool can make things bigger, more complex, and more violent. It takes a touch of genius - and a lot of courage - to move in the opposite direction. - Ernst F. Schumacher
You can easily add different types of objects to a Vector. In fact, this is one of the advantages of the Container API and, contrary to your claim, this is a VERY OO approach to the problem at hand. Adding objects isn't a problem, however retrieving them can be. If the functionality you need is in the Order base class, you can simply cast all objects to Order when you pull them out and ignore the concrete type of the objects. If you absolutely need the whole functionality of the child class, then you can use instanceof to detect what type it is, just like you said you thought of. However, I personally would just use a cast and check if the result is not null. Honestly, I don't know which is more efficient, but since you have to do a cast even when you use instanceof, leaving out the instanceof part is less code to type. [ April 25, 2003: Message edited by: Layne Lund ]
Layne, this might not be what you meant to say, but "just use a cast and check if the result is not null" almost reads as if casting an OrderA object to OrderB type will result in a null value. It will of course throw an exception. I agree with you that adding different flavours of Order to a Vector (well, preferably a List implementation from the Collections framework such as ArrayList) is a very OO thing to do. Michael, too, is absolutely right when he says that you don't want nonsensical state in the Order base class. However, the need for instanceof and casts is a bit of a code smell. You're using them to do different things depending on the precise type of the Order. This is, of course, exactly what polymorphism was designed to handle for you! I'll suggest two ways you can leverage polymorphism to address your problem. I'm not saying they're "better" than the instanceof solution discussed so far. Sometimes they are, sometimes they aren't; I don't know enough about your problem to make that decision for you. I will assume that type A orders have some extra attribute called FooBar. The first way would be decide that an Order is something that might or might not have a FooBar attribute, which is undeniably true. Correspondingly, an Order should have a getter that might or might not return a value.Although there is this getter in Order for FooBar, only OrderA objects contain any actual state corresponding to this attribute. In your JSP you can check the value returned for fooBar to decide if you need to display that attribute or not. The second alternative is in some ways more elegant, but might be less practical in a JSP context. It uses double dispatch to avoid any testing of object types or return values.The cute thing is that the usual Java method overloading rules ensure that OrderDisplay will display order details as accurately as it can. OrderA has its own display method. In the code shown above, OrderB will use the generic Order display code. If there's something specific you want to display for OrderB objects, you just add a display(OrderB order) method without changing any of the actual Order classes. This double dispatch method is a way to take a specific concern (displaying, in this case) that would otherwise be spread over all the classes in a hierarchy, and concentrate it all in a single class. It is most useful for concerns which are not really part of the classes' responsibility. For example, the purpose of an Order is to encapsulate order state. It shouldn't have to worry about how it is being displayed, how it is being fulfilled, and so forth. Does this help? - Peter