Niall
Niall

Reputation: 1621

Iterating over different objects descended from same base class

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

Answers (3)

jbaliuka
jbaliuka

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

Florian
Florian

Reputation: 111

Try to use List<? extends MusicComponent> as return type

Upvotes: 3

Omoro
Omoro

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

Related Questions