创建递归迭代器

Nia*_*all 7 java recursion android

我正在尝试为类的层次结构编写迭代器,这些类共同构成了歌曲的组成部分.所有类都是抽象MusicComponent基类的实现并继承了一个getChildren()函数.抽象MusicTime子类都知道实际的音符/和弦玩,和所有的实施方式(例如八分音符,四分音符)回报nullgetChildren().

其他组件MusicComponent一次保存MusicTimes例如条形的集合,并且Section保持该组合MusicComponents.Song拥有Sections构成歌曲的歌曲,例如诗歌,合唱,具有不同节奏/时间签名的部分.

我需要的是一个迭代器,将通过所有迭代SectionsSong,那么所有MusicComponentsSection,只有当它找到一个MusicTime传人,演奏的音符为基础的音符类型的时间长度,时间签名和节奏包含其的Section.

对不起,如果信息太多,但是我能解释我正在尝试做什么的唯一方法.那么我是否需要使用堆栈来处理这个问题,MusicComponents我已经访问过哪些记录,或者只是使用递归来实现这一点?

Mat*_*ens 5

您可以编写一个迭代器来“连接”其子迭代器,甚至是懒惰的。然后调用next()aSong的迭代器将向下钻取SectionMusicComponent迭代器,最后交付下一个MusicTime

番石榴使这变得容易。制作MusicComponentIterable<MusicTime>实施iterator()为:

@Override
public Iterator<MusicTime> iterator() {
    return Iterables.concat(getChildren()).iterator();
}
Run Code Online (Sandbox Code Playgroud)

由于所有子级都是MusicComponents 并因此实现Iterable<MusicTime>它们自己,Song因此 的迭代器将是迭代器的串联Section,而迭代器本身也是MusicTime迭代器的串联。

最后一个迭代器是一个特例。迭代MusicTime器应该只返回自身一次:

@Override
public Iterator<MusicTime> iterator() {
    return Iterators.singletonIterator(this);
}
Run Code Online (Sandbox Code Playgroud)

或者,Section的迭代器可以替换为:

@Override
public Iterator<MusicTime> iterator() {
    return getChildren().iterator();
}
Run Code Online (Sandbox Code Playgroud)

有了这个,迭代就变得很简单:

for (MusicTime time : song) {
    player.play(time);
}
Run Code Online (Sandbox Code Playgroud)

您现在可以执行任何类型的操作(播放、计算总持续时间……),而无需重新实现递归。

虽然您的问题有其他解决方案,但这一切都取决于设计选择。例如,您可以拥有一个play方法,并MusicComponent通过调用其所有子级来实现该方法。这是一个简单的递归实现,但是您必须对要添加的所有操作重复递归(例如,SongSectionplayMusicComponentplaygetTotalDuration、...)重复递归。

如果您需要更大的灵活性,您可以使用访问者设计模式并使您的播放操作成为访问者(例如PlayVisitor)。这样做的优点是您可以决定从访问者内部控制迭代顺序,但会增加添加新MusicComponent实现的难度。