让我们尝试实现这个功能。播放随机曲目有什么要求?
- 它应该是随机的(当然),
- 它应该不是当前曲目(如果还有其他曲目要播放,没有人愿意连续听五次当前曲目)
- 您应该从播放器中存在的曲目中选择曲目(曲目编号不应超过曲目数量)。
我将使用 C#:
Random random = new Random();
CDPlayer player = new CDPlayer();
// creates list of track indexes, e.g. { 1, 2, 3, 4, 5, 6, 7 }
var tracksNotPlayed = Enumerable.Range(0, player.NumberOfTracks - 1).ToList();
if(tracksNotPlayed.Count == 0)
// initialize list again, or stop
int index = random.Next(tracksNotPlayed.Count);
int nextTrack = tracksNotPlayed[index];
player.SetCurrentTrack(nextTrack);
tracksNotPlayed.Remove(nextTrack);
对我来说,这看起来像是功能羡慕- 其他一些类使用来自播放器的数据来实现此功能。不好。让我们进行一些重构 - 将所有这些东西移到播放器中:
public void PlayRandomTrack() // Shuffle
{
if(tracksNotPlayed.Count == 0)
tracksNotPlayed = Enumerable.Range(0, numberOfTracks - 1).ToList();
int index = random.Next(tracksNotPlayed.Count);
int nextTrack = tracksNotPlayed[index];
SetCurrentTrack(nextTrack);
tracksNotPlayed.Remove(nextTrack);
}
它看起来更好,并且更容易在外面使用:
CDPlayer player = new CDPlayer();
player.PlayRandomTrack();
此外,如果您正在实现诸如 Winamp 之类的东西(它有两种模式 - 随机播放和顺序播放,当它一首自动播放歌曲时)然后考虑将此逻辑移动到一些策略中(或者它应该是Iterator?),它将有两个实现 - 顺序和随机播放,并且对播放器一无所知 - 它的责任是在某个范围内选择数字(应该传递被枚举的轨道或集合的数量):
public abstract class CollectionIterator<T>
{
public CollectionIterator(IEnumerable<T> source)
{
// save source
}
abstract int GetNextItemIndex();
}
播放器将使用此迭代器/策略来播放下一个项目:
public void PlayTrack()
{
SetCurrentTrack(iterator.GetNextItemIndex());
}
所以,我们在这里有明确的职责分离——客户端使用播放器来听音乐,播放器知道如何播放音乐,迭代器知道如何从集合中选择下一个项目。ThursdaysCollectionIterator
如果您想在星期四创建一些其他序列,您可以创建。这将使您的播放器和客户端代码保持不变。