Problem Statement
Design a music playlist iterator that allows traversing the playlist in different ways
in order (from start to end)
reverse (from end to start)
shuffled (in random order)
Understanding Iterator Design Pattern
This behavioral design pattern allows access to the elements of an aggregate object or collection without exposing underlying representations.
Blueprint of the Iterator Design Pattern
The Iterator design pattern involves the following key components:
Iterator Interface: Defines the interface for accessing and traversing elements.
Concrete Iterator: Implements the
Iterator
interface and keeps track of the current position in the traversal of the aggregate.Aggregate Interface: Defines the interface for creating an
Iterator
object.Concrete Aggregate: Implements the
Aggregate
interface and returns an instance of theConcrete Iterator
.
Solution
Defining the data model
public class Song {
private String title;
private String artist;
public Song(String title, String artist) {
this.title = title;
this.artist = artist;
}
public String getTitle() {
return title;
}
public String getArtist() {
return artist;
}
@Override
public String toString() {
return title + " by " + artist;
}
}
Defining Iterator Interface
PlaylistIterator: Provides methods for traversing the playlist
public interface PlaylistIterator {
boolean hasNext();
Song next();
}
Defining Concrete Iterator Classes
InOrderPlaylistIterator: Traverses the playlist from start to end
import java.util.List;
import java.util.NoSuchElementException;
public class InOrderPlaylistIterator implements PlaylistIterator {
private List<Song> songs;
private int position;
public InOrderPlaylistIterator(List<Song> songs) {
this.songs = songs;
this.position = 0;
}
@Override
public boolean hasNext() {
return position < songs.size();
}
@Override
public Song next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return songs.get(position++);
}
}
ReversePlaylistIterator: Traverses the playlist from end to start.
import java.util.List;
import java.util.NoSuchElementException;
public class ReversePlaylistIterator implements PlaylistIterator {
private List<Song> songs;
private int position;
public ReversePlaylistIterator(List<Song> songs) {
this.songs = songs;
this.position = songs.size() - 1;
}
@Override
public boolean hasNext() {
return position >= 0;
}
@Override
public Song next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return songs.get(position--);
}
}
ShufflePlaylistIterator: Traverses the playlist in random order.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class ShufflePlaylistIterator implements PlaylistIterator {
private List<Song> shuffledSongs;
private int position;
public ShufflePlaylistIterator(List<Song> songs) {
this.shuffledSongs = new ArrayList<>(songs);
Collections.shuffle(shuffledSongs, new Random());
this.position = 0;
}
@Override
public boolean hasNext() {
return position < shuffledSongs.size();
}
@Override
public Song next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return shuffledSongs.get(position++);
}
}
Defining the Aggregate Interface
PlaylistAggregate Interface: Defines methods to create iterators for different traversal strategies.
public interface PlaylistAggregate {
PlaylistIterator createInOrderIterator();
PlaylistIterator createReverseIterator();
PlaylistIterator createShuffleIterator();
}
Defining Aggregate Class - Playlist
import java.util.ArrayList;
import java.util.List;
public class Playlist implements PlaylistAggregate {
private List<Song> songs;
public Playlist() {
this.songs = new ArrayList<>();
}
public void addSong(Song song) {
songs.add(song);
}
public List<Song> getSongs() {
return songs;
}
@Override
public PlaylistIterator createInOrderIterator() {
return new InOrderPlaylistIterator(songs);
}
@Override
public PlaylistIterator createReverseIterator() {
return new ReversePlaylistIterator(songs);
}
@Override
public PlaylistIterator createShuffleIterator() {
return new ShufflePlaylistIterator(songs);
}
}
Main
Here's how we can use PlaylistIterator
and its iterators in the MusicApp
public class MusicApp {
public static void main(String[] args) {
Playlist playlist = new Playlist();
playlist.addSong(new Song("Song 1", "Artist 1"));
playlist.addSong(new Song("Song 2", "Artist 2"));
playlist.addSong(new Song("Song 3", "Artist 3"));
PlaylistIterator inOrderIterator = playlist.createInOrderIterator();
System.out.println("In-Order Playlist: ");
while (inOrderIterator.hasNext()) {
System.out.println(inOrderIterator.next());
}
PlaylistIterator reverseIterator = playlist.createReverseIterator();
System.out.println("Reverse Playlist: ");
while (reverseIterator.hasNext()) {
System.out.println(reverseIterator.next());
}
PlaylistIterator shuffleIterator = playlist.createShuffleIterator();
System.out.println("Shuffled Playlist: ");
while (shuffleIterator.hasNext()) {
System.out.println(shuffleIterator.next());
}
}
}
Let's connect ๐งโ๐ป