I'm not sure your experience level with object-oriented programming, but the very, very short answer to your question is yes, you would use polymorphism, which could be handled through inheritance or with Interfaces (you can also combine the two.) I'll briefly discuss the interface option, as I generally think it's a better way to go.
classes and interfaces define types. So a class that implements an interface is of its class type as well as the interface type(every object in Java is also, at least, of type Object-through inheritance.) Types control pretty much everything in OOP, especially the connection of an instance to its properties/methods. When objects of different types, or classes, need to work together, as in your example, you need a way of passing object references. In your solution, you buried an object reference in another class. This works, but I think you see the problem with scaling that approach. As you add more objects, you need to add more references and do more checking in the constructor, perhaps using the instanceof operator-not a good solution. However, Java has a very cool feature called dynamic binding, which makes polymorphism possible providing a much better solution to your problem.
Dynamic binding allows the linking of an instance and its type to occur at runtime. In other words, an instance type can be left somwhat anonymous at compilation and, later at runtime, more specifically defined. To understand how this might help in your program, here's a Pizza example (sorry I'm hungry.)
Let's say you wanted to create a virtual Pizza, with 20 different toppings, each a separate class. Using your initial solution you'd have to bury references to each of the 20 toppings in the Pizza class. Then if you ever wanted add more toppings, you'd need to go back into the class...not good. A better solution is to create an interface, which I'll call
ITastyToppings. To keep things simple, we'll just give the interface a single
create() method. Interfaces don't implement their methods, but rather just include a method declaration, for example, here's our really simple interface:
Code:
interface ITastyToppings {
void create();
}
Next we'd create our 20 toppings classes and each class would implement the ITastyToppings interface. By implementing the interface, each instance of a respective toppings class will also be of type ITastyToppings. Each class that implements the interface is required to implement the
create() method. This will allow each class to implement the method in their own way. So Meatballs can be slow-cooked in sauce all day, while mushroooms can be sauteed, etc. The Pizza class will include reference variables of type ITastyToppings. When the Pizza is instantiated, the Toppings object references can be passed to the Pizza constructor and caught by parameters of type ITastyToppings, since each of the different Toppings instances are also of the common type ITastyToppings.
Here's the really cool part: when each of the ITastyToppings references calls the
create() method, Java automatically figures out which respective version of the method to call, based on the specific Toppings class.
The solution is scalable now. You can go hogwild and add as many new toppings as you want, as long as each new toppings class implements the ITastyToppings interface.
It's now 3:30 am, and I think it's time to sleep.