Reputation: 1621
I have various classes which define the structural elements of a piece of music. The hierarchy is Song
> Section
> CompositeMusic
> MusicTime
, all of which inherit from an abstract MusicComponent
class.
MusicTime
is the bottom level and knows which Chord
to play and for how many crotchets, and are contained in bars in CompositeMusic
objects. Section
in turn holds the CompositeMusics
and is there to allow for tempo and time signature changes.
I need to be able to recursively iterate through all Sections
in the Song
, all CompositeMusics
in each Section
, and play all MusicTimes
in each CompositeMusic
. In other words, iterate through all the children in each type unless it's a MusicTime
in which case play it.
I naively thought I would be able to put an abstract List<MusicComponent> getChildren()
on the MusicComponent
base class so I could iterate over any descendant in the same way. However this isn't allowed as it won't accept a List<Section>
for example.
So my question is, what is the correct method to recursively iterate over different objects descended from the same base class?
EDIT
Code samples, as requested:
Base class
public abstract class MusicComponent {
public MusicComponent() {
}
public abstract void play();
public abstract boolean addComponent(MusicComponent component);
public abstract List<MusicComponent> getChildren();
}
Example of sub class
public class Song extends MusicComponent {
String songName;
List<Section> sections;
public Song(String songName, List<Section> sections) {
this.songName = songName;
this.sections = sections;
}
This is what I want to do on Song
(and equivalent for Section
and CompositeMusic
)
@Override
public List<MusicComponent> getChildren() {
return sections;
}
But it throws an compile error as it can't implicitly convert from List<Section>
to List<MusicComponent>
even though Section
is descended from MusicComponent
, which is what I'd hoped to be able to do
Upvotes: 0
Views: 105
Reputation: 259
Please see Visitor design pattern in Wikipedia. It is a classic way to recursively iterate complex hierarchy. Design patterns is overhead for simple use cases but it can help if your model will evolve in the future.
Upvotes: 0
Reputation: 972
From Java 1.5 covariant return types are supported so basically the method getChildren() will be able to return any list of the subclasses of MusicComponent if the base class method is overriden. What you need to do is before you iterate check using instanceof to make sure that the list variable that you want to iterate is of the correct type.
Upvotes: 0