创建一个递归迭代
我试图写一个迭代器类,它们共同构成了一首歌曲的组件层次。所有的类都是抽象的 MusicComponent
基类的实现,并继承的getChildren()
功能。摘要 MusicTime
子知道实际的音符/和弦玩,和它的所有实现(例如八分音符,四分音符)返回空
为的getChildren()
。
I am trying to write an iterator for a hierarchy of classes that collectively make up the components of a song. All classes are implementations of the abstract MusicComponent
base class and inherit a getChildren()
function. The abstract MusicTime
subclass knows the actual note/chord to play, and all its implementations (e.g. quaver, crotchet) return null
for getChildren()
.
其它部件 MusicComponent
持有 MusicTimes
的集合,例如酒吧的时间,而科
持有的 MusicComponents
。 歌曲
持有部分
组成的歌曲如:诗句,合唱团,用不同的节奏节/时的签名。
The other components are MusicComponent
which holds a collection of MusicTimes
e.g. a bar at a time, and Section
which holds the MusicComponents
. Song
holds the Sections
that make up the song e.g. verses, choruses, sections with different tempos/time signatures.
我需要的是一个迭代,将遍历所有部分
在歌曲
,那么所有的 MusicComponents
在科
,只有当它找到一个 MusicTime
传人,戏剧音符的时间是根据它的音符类型的长度,其含有部分的拍号和速度
。
What I need is an iterator that will iterate through all Sections
in a Song
, then all MusicComponents
in the Section
and only when it finds a MusicTime
descendant, play the note for the length of time based on its note type, and the time signature and tempo of its containing Section
.
抱歉,如果太多的信息,但只有这样,我可以解释我想要做的。所以,我需要处理这一堆,记录其中 MusicComponents
我visted或者是有没有办法这个只是用递归做?
Sorry if too much info, but was the only way I could explain what I'm trying to do. So do I need to handle this with a stack, recording which MusicComponents
I've visted or is there a way to do this just using recursion?
您可以写一个迭代器会连接其子的迭代器,甚至懒洋洋地。呼叫下一个()
在歌曲
的迭代器,然后将深入挖掘科
和 MusicComponent
迭代器和最终实现下一个 MusicTime
。
You can write an iterator which "concatenates" the iterators of its children, even lazily. Calling next()
on a Song
's iterator would then drill down through the Section
and MusicComponent
iterators and finally deliver the next MusicTime
.
番石榴使这个容易。让 MusicComponent
的可迭代< MusicTime>
和实施迭代器()
为:
Guava makes this easy. Make MusicComponent
an Iterable<MusicTime>
and implement iterator()
as:
@Override
public Iterator<MusicTime> iterator() {
return Iterables.concat(getChildren()).iterator();
}
由于所有的孩子都 MusicComponent
和由此实施可迭代&LT; MusicTime&GT;
自己,宋
的迭代器将部分的串联
迭代器,这本身就是 MusicTime
的串联>迭代器。
Since all children are MusicComponent
s and thus implement Iterable<MusicTime>
themselves, Song
's iterator will be a concatenation of Section
iterators, which are themselves concatenations of MusicTime
iterators.
这最后的迭代器是一种特殊情况。 A MusicTime
迭代器只能返回自己一次:
This last iterator is a special case. A MusicTime
iterator should only return itself once:
@Override
public Iterator<MusicTime> iterator() {
return Iterators.singletonIterator(this);
}
另外,科
的迭代器可以改为:
Alternatively, Section
's iterator could be replaced with:
@Override
public Iterator<MusicTime> iterator() {
return getChildren().iterator();
}
通过这一点,迭代变得那么容易,因为:
With this, iterating becomes as easy as:
for (MusicTime time : song) {
player.play(time);
}
您现在可以做任何类型的操作(播放,计算总工期,...)无需重新执行递归。
You can now do any kind of operation (playing, counting the total duration,...) without re-implementing the recursion.
有您的问题的替代解决方案,虽然,但是这一切都归结到设计选择。例如,你可以有一个播放
在 MusicComponent
其中歌曲$ C $方法C>和
科
通过调用将实施播放
所有子女。这是一个简单的递归实现,但你必须为你要添加的 MusicComponent
(如所有行动中发挥重复递归
, getTotalDuration
,...)。
There are alternative solutions for your problem though, but it all comes down to design choices. For example, you could have a play
method on MusicComponent
which Song
and Section
would implement by calling play
on all of their children. This is a straightforward recursive implementation, but you must repeat the recursion for all operations you intend to add on MusicComponent
(such as play
, getTotalDuration
, ...).
如果您需要更多的灵活性,您可以使用 Visitor设计模式并让您的播放操作访客(如 PlayVisitor
)。这样做的好处是,你可以决定控制从游客中的迭代顺序,但使得它很难增加新的 MusicComponent
的实施。
If you need more flexibility, you could use the Visitor design pattern and make your play operation a visitor (e.g. PlayVisitor
). This has the advantage that you can decide to control the iteration order from within the visitor, but makes it harder to add new MusicComponent
implementations.