Reputation: 6148
I am making a storehouse system(use OOP) and of course there are many goods in it. I want to have a ArrayList(or some other containers) to hold those goods, so I can change less code when the goods change from lights to cups(subclass of goods). It seems can be fulfilled by extends/implements the class Goods. But when I get the input of user, it seems I have to use many if-else if I have many subclass.
like this:
if(name == Light){list.add(new Light(...)}
if(name == Cup){list.add(new Cup(...)}
...
And when I get the goods from the list, it seems that I have to use instanceof
like this:
if(goods instanceof Light){}
if(goods instanceof Cup) {}
...
So the code become not so elegant at all. So my question is how can I solve this problem.
Upvotes: 0
Views: 85
Reputation: 560
As OO thingking: DO NOT program to see what object do you have, just use them. Don't tell what to do when you calling an object, they should know the method themselves.
In following demo, the CupLight is a kind of Goods, and you can have more kinds of Goods.
When you use them, just tell them do the job, I mean call the method saySomething().
No if-else is needed in this situation
public class Test {
public interface Goods {
public void whoAmI();
}
public static class Light implements Goods {
@Override
public void whoAmI() {
System.out.println("I'm a Light");
}
}
public static class Cup implements Goods {
@Override
public void whoAmI() {
System.out.println("I'm a Cup");
}
}
public static class CupLight extends Light {
public void saySomething() {
whoAmI();
}
}
public static void main(String[] args) {
new CupLight().saySomething();
}
}
Upvotes: 1
Reputation: 54639
The questions from the comments are certainly justified: When you store the Goods as Goods, at which point in time (and why) is it relevant what type these elements have?
Of course, one could imaginge scenarios where this information is necessary. But one should definitely consider a different structure when this is the primary way of using these classes. For example, one then might consider something like a
Map<Class<?>, List<?>> mapFromClassToListOfObjectsWithThisClass;
that can be maintained (in a type-safe way) internally - but that's just a first, rough idea.
In any case, you should avoid many instanceof
clauses. Particularly when the intention is to extend this system with other types later. You certainly do not want to be forced to re-compile your code when some client introduces a new subtype of Good
.
You could then consider to use a method that allows extracting the objects of a particular type from a given list:
import java.util.ArrayList;
import java.util.List;
public class TypeListFilterTest
{
public static void main(String[] args)
{
List<Number> list = new ArrayList<Number>();
list.add(Integer.valueOf(12));
list.add(Double.valueOf(12.34));
list.add(Float.valueOf(23.45f));
list.add(Integer.valueOf(34));
list.add(Float.valueOf(34.56f));
List<Float> floats = filter(list, Float.class);
System.out.println("Floats : "+floats);
List<Integer> integers = filter(list, Integer.class);
System.out.println("Integers: "+integers);
}
private static <T> List<T> filter(Iterable<?> list, Class<T> t)
{
List<T> result = new ArrayList<T>();
for (Object object : list)
{
if (t.isInstance(object))
{
result.add(t.cast(object));
}
}
return result;
}
}
In the best case, this method could replace the instanceof
tests, and would allow treating different types, leaving the responsibility to be aware of these types to the client code. This way, the classes could handle new types, without having to be recompiled with new instanceof
checks.
But based on the current problem description, this is also only a first idea, that may or may not be applicable in your case.
Upvotes: 1
Reputation: 926
I propose you trade your "if-else" statements for Chain of Responsibility pattern.
Chain of responisibility on wikipedia
Enjoy :)
Upvotes: 0