Reputation: 45
I've got an interesting and troublesome task to solve. I need to create a playlist (some kind of list) that contains songs and other sub-playlists of songs... Each playlist has a playing mode (random, sequence, etc.) Is it possible to create such playlist? I thought about cracking the sub-playlists and adding extraxted songs from it to the master playlist or creating a sub-playlist for every song that is added to master playlist (I don't really like this idea) Somehow it gets around the problem however it is necessary to remain playing mode of each playlist...
For example:
Master playlist(sequence palymode) has: (1) song1-1/ (2) subplaylist(song2-1, song2-2, song-2-3) with random playmode/ (3) song1-2
The desired outcome: (1) song1-1/ (2) song2-3 (starting random subplaylist)/ (3) song2-1/ (4) song2-2/ (5) song1-2/
how should I approach this?
Upvotes: 1
Views: 320
Reputation: 960
Approach 1: Create a class named playlist and playlist item which can hold list of songIds, which can hold set of songs from different playlists or song ids.
class PlayList{
List<PlayListItem> playlistItems;
}
class PlayListItem{
List<String> songIds;
}
This helps if a particular if you want to identify the set of songs added via a particular sub playlist. However this approach makes the iteration little difficult compared to approach 2
Approach 2: Here the list is avoided in playlist item, so that iteration while displaying playlist is simple. However to identify the list of songIds that was added via a particularSubPlaylist has to be computed.
class PlayList{
List<PlayListItem> playlistItems;
}
class PlayListItem{
String songId;
String referencePlayListId;
}
Upvotes: 0
Reputation: 2863
Altough there are already some answers, i promised to provide a sample implementation. Starting of we have a common interface Playable
which is the class to be implemented for the composite design pattern.
public interface Playable {
String getSongName();
}
Next, the Song
class to represent a single song.
public class Song implements Playable {
private String name;
public Song(String name) {
this.name = name;
}
@Override
public String getSongName() {
return name;
}
}
In preparation for the Playlist
class an enum to represent the difference playing modes.
public enum PlayingMode {
SEQUENCE, RANDOM
}
Now, finally the playlist class.
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);
}
}
Some examples:
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();
}
}
Could give the output:
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
You can also add songs while playing:
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"));
}
}
This could lead to:
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
Some final notes:
getIndex
method does have a worst case runtime of O(n), which can be an issue if there are many songs in the playlist. A faster Collection
like Set
or Map
will give better performace, but the implementation is a bit more complex.Upvotes: 1
Reputation: 298
Since I suspect that this is some sort of homework, I will only provide you with a partial implementation, so you get an idea how to proceed.
Create an abstract class PlaylistElement
, which can later either be a Song
or another Playlist
.
abstract class PlaylistElement {
public abstract List<Song> printSongs();
}
Implement a class Playlist
extending 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;
}
}
Implement a class Song
extending 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 });
}
}
Create an enum for your Playlist Playback Modes.
enum PlaybackMode {
SEQUENTIAL, RANDOM;
}
Hope this gives you a general idea! Getters/Setters and other important parts omitted for brevity.
Upvotes: 3