【问题标题】:Object + List of Objects in a List?对象+列表中的对象列表?
【发布时间】:2019-02-03 11:32:41
【问题描述】:

我有一个有趣而麻烦的任务要解决。 我需要创建一个包含歌曲和其他歌曲子播放列表的播放列表(某种列表)...每个播放列表都有一个播放模式(随机、序列等)。是否可以创建这样的播放列表? 我想过破解子播放列表并将提取的歌曲添加到主播放列表中,或者为添加到主播放列表的每首歌曲创建一个子播放列表(我不太喜欢这个想法) 不知何故,它解决了这个问题,但是有必要保持每个播放列表的播放模式......

例如:

主播放列表(序列播放模式)具有: (1) 歌曲1-1/ (2) 随机播放模式的子播放列表(song2-1, song2-2, song-2-3)/ (3) 歌曲1-2

期望的结果: (1) 歌曲1-1/ (2) song2-3(开始随机子播放列表)/ (3) 歌曲2-1/ (4) 歌曲2-2/ (5) 歌曲1-2/

我应该如何处理这个问题?

【问题讨论】:

  • 确实很有趣。你试过什么了?听起来像家庭作业,而且范围太广,因为没有尝试解决它。​​
  • 老实说,我完全停留在构思步骤本身......我在管理收藏和模拟这样的播放列表播放器方面没有问题。我只是不知道如何提供子播放列表存在
  • 复合设计模式呢?你有一个播放列表和一首歌曲作为叶子。播放列表需要跟踪当前元素。如果它是一首歌曲,则返回它,如果它是另一个播放列表,则调用它的 get song 方法,直到没有更多歌曲(可能返回 null 或 Optional#empty)。
  • 从未听说过这种设计模式,但经过简短的了解后,我可以说这就是解决这个问题的方法。我要试试。谢谢!
  • 如果你喜欢,我可以给你一个示例实现

标签: java list


【解决方案1】:

由于我怀疑这是某种家庭作业,因此我只会为您提供部分实现,以便您了解如何进行。

创建一个抽象类PlaylistElement,以后可以是Song 或另一个Playlist

abstract class PlaylistElement {
    public abstract List<Song> printSongs();
}

实现一个类 Playlist 扩展 PlaylistElement

class Playlist extends PlaylistElement {
    private List<PlaylistElement> elements;
    private PlaybackMode playbackMode;
    @Override
    public List<Song> printSongs() {
        if(this.playbackMode == PlaybackMode.RANDOM) {
            List<Song> songs = new ArrayList<>();
            List<PlaylistElement> shuffleElements = new ArrayList<>();

            //Add all PlaylistElements from elements into shuffleElements
            //and shuffle the shuffleElements collection

            //insert your songs into the songs collection here by sequentially
            //going through your
            //PlaylistElements and inserting the result of their printSongs()
            //implementation (e.g. in a for-loop)

            return songs;
        }
        else if(this.playbackMode == PlaybackMode.SEQUENTIAL) {
            //you can do this on your own
        }
        return null;
    }
}

实现一个类 Song 扩展 PlaylistElement

class Song extends PlaylistElement {
    private String title;
    private String artist;
    .
    .
    .
    @Override
    public List<Song> printSongs() {
        //return a List with only this Song instance inside
        return Arrays.asList(new Song[] { this });
    }
}

为您的播放列表播放模式创建一个枚举。

enum PlaybackMode {
    SEQUENTIAL, RANDOM;
}

希望这能给您一个总体思路!为简洁起见,省略了 Getter/Setter 和其他重要部分。

【讨论】:

  • 我在考虑。最后,看起来我必须将我的单曲放在一个元素列表中。我认为这是可以避免的。嗯,这应该工作。谢谢
  • 很高兴我能帮上忙。
【解决方案2】:

虽然已经有了一些答案,但我承诺提供一个示例实现。首先我们有一个公共接口Playable,它是复合设计模式要实现的类。

public interface Playable {
    String getSongName();
}

接下来,Song 类代表一首歌曲。

public class Song implements Playable {

    private String name;

    public Song(String name) {
        this.name = name;
    }

    @Override
    public String getSongName() {
        return name;
    }
}

在为Playlist 类做准备时,一个枚举来表示不同的播放模式。

public enum PlayingMode {
    SEQUENCE, RANDOM
}

现在,终于是播放列表类了。

public class Playlist implements Playable {

    private String name;
    private List<Playable> playables = new ArrayList<>();
    private PlayingMode mode;

    private Playable currentItem;
    private List<Playable> next = new ArrayList<>();

    public Playlist(String name, PlayingMode mode) {
        this.name = name;
        this.mode = mode;
    }

    @Override
    public String getSongName() {
        if (playables.isEmpty()) {
            return null;
        }

        if (currentItem == null) {
            // initialize the playing songs
            next.addAll(playables);
            if (mode == PlayingMode.RANDOM) {
                Collections.shuffle(next);
            }
            currentItem = next.get(0);
        } else {
            // if we have a playlist, play its songs first
            if (currentItem instanceof Playlist) {
                String candidate = currentItem.getSongName();
                if (candidate != null) {
                    return candidate;
                }
            }

            int index = next.indexOf(currentItem);
            index++;
            if (index < next.size()) {
                currentItem = next.get(index);
            } else {
                currentItem = null;
            }
        }

        return currentItem != null ? currentItem.getSongName() : null;
    }

    private void addToNext(Playable playable) {
        if (currentItem == null) {
            return;
        }

        // if the playlist is playing, add it to those list as well
        if (mode == PlayingMode.SEQUENCE) {
            next.add(playable);
        } else if (mode == PlayingMode.RANDOM) {
            int currentIndex = next.indexOf(currentItem);
            int random = ThreadLocalRandom.current().nextInt(currentIndex, next.size());
            next.add(random, playable);
        }
    }

    public void addPlayable(Playable playable) {
        Objects.requireNonNull(playable);
        playables.add(playable);
        addToNext(playable);
    }
}

一些例子:

public static void main(String[] args) {
    Song song1 = new Song("Song 1");
    Song song2 = new Song("Song 2");

    Playlist subPlaylist1 = new Playlist("Playlist 1", PlayingMode.RANDOM);
    subPlaylist1.addPlayable(new Song("Song A"));
    subPlaylist1.addPlayable(new Song("Song B"));
    subPlaylist1.addPlayable(new Song("Song C"));

    Song song3 = new Song("Song 3");

    Playlist main = new Playlist("Main", PlayingMode.SEQUENCE);
    main.addPlayable(song1);
    main.addPlayable(song2);
    main.addPlayable(subPlaylist1);
    main.addPlayable(song3);

    String songName = main.getSongName();
    while (songName != null) {
        System.out.println("Current song is: " + songName);
        songName = main.getSongName();

    }
}

可以给出输出:

Current song is: Song 1
Current song is: Song 2
Current song is: Song B
Current song is: Song A
Current song is: Song C
Current song is: Song 3

您还可以在播放时添加歌曲:

while (songName != null) {
    System.out.println("Current song is: " + songName);
    songName = main.getSongName();

    // add songs while playing
    if ("Song A".equals(songName)) {
        subPlaylist1.addPlayable(new Song("Song D"));
        subPlaylist1.addPlayable(new Song("Song E"));
        subPlaylist1.addPlayable(new Song("Song F"));
    }
}

这可能导致:

Current song is: Song 1
Current song is: Song 2
Current song is: Song B
Current song is: Song A
Current song is: Song E
Current song is: Song D
Current song is: Song F
Current song is: Song C
Current song is: Song 3

一些最后的笔记:

  • getIndex 方法确实有 O(n) 的最坏情况运行时间,如果播放列表中有很多歌曲,这可能是个问题。更快的Collection(如SetMap)会提供更好的性能,但实现会稍微复杂一些。
  • 类已被简化,这意味着一些 gettersetter 以及 equalshashCode为简洁起见被省略。

【讨论】:

  • 谢谢,我做得更简单了。我认为由于当前项目和迭代器的这些条件,列表中的迭代太复杂了。无论如何,总体思路很棒。
【解决方案3】:

方法一: 创建一个名为 playlist 和 playlist item 的类,它可以保存 songIds 列表,它可以保存来自不同播放列表或歌曲 ID 的歌曲集。

class PlayList{
  List<PlayListItem> playlistItems;
}

class PlayListItem{
  List<String> songIds;
}

如果您想识别通过特定子播放列表添加的歌曲集,这将很有帮助。然而,与方法 2 相比,这种方法使迭代变得不那么困难

方法二: 这里在播放列表项中避免了列表,因此显示播放列表时的迭代很简单。但是,必须计算通过特定子播放列表添加的歌曲 ID 列表。

class PlayList{
  List<PlayListItem> playlistItems;
}
class PlayListItem{
  String songId;
  String referencePlayListId;
}

【讨论】:

  • 感谢您的回答。不幸的是,这两种方法都不允许在播放列表中的播放列表中有歌曲。方法 1 迫使我为要添加的每首歌曲创建一个单独的播放列表。只是不确定这是否是正确的做法。方法 2 不允许我在另一方面添加单曲。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-24
  • 2014-01-15
  • 1970-01-01
相关资源
最近更新 更多