The domain model of my application revolves around movies.
Use case:
We have a movie for which only one title (in one country) is known and we want to know titles of this movie in other countries. To get that information, we call external movie repositories.
The Movie
class has a map of titles in countries. It also has a list of external IDs. For example, we might know that IMDB's ID for the movie Breakfast at Tiffany's is tt0054698.
class Movie {
private Map<Country, String> titles;
private Year yearOfRelease;
private Map<ExternalMovieRepository, String> externalIds;
public Map<Country, String> titles() {
return titles;
}
public Year yearOfRelease() {
return yearOfRelease;
}
public Map<ExternalMovieRepository, String> externalIds() {
return externalIds;
}
}
The ExternalMovieRepository
enum
is used as a key to which external ID value is mapped.
enum ExternalMovieRepository {
IMDB, ROTTEN_TOMATOES;
}
The classes representing the external movie repositories will be able to find additional information only for Movie
instances carrying some information the repository requires.
For example, RottenTomatoesMovieRepository
requires the Movie instance either to have a US movie title (<Country, String>
map entry) or the Rotten Tomatoes' external ID in its externalId
s map.
Here is a draft for an interface that could represent the external repositories:
/**
* Finds movie title for other countries using information from Movie.
*
*/
interface MovieTitleFinder {
boolean accepts( Movie m );
Map<Country, String> findTitles( Movie m );
}
An implementation could look like this:
class RottenTomatoesTitleFinder implements MovieTitleFinder {
private final String US_ISO = "us";
private CountryRepository countryRepository;
RottenTomatoesTitleFinder( CountryRepository countryRepository ) {
this.countryRepository = countryRepository;
}
@Override
public boolean accepts( Movie m ) {
return ( getUSTitle( m ) != null || getRTId( m ) != null );
}
@Override
public Map<Country, String> findTitles( Movie m ) {
String rtId = getRTId( m );
if ( rtId != null ) {
return findByRTid( rtId );
}
String usTitle = getUSTitle( m );
if ( usTitle != null ) {
return findByUSTitle( usTitle );
}
return Collections.emptyMap();
}
private String getUSTitle( Movie m ) {
Country us = countryRepository.findByIso( US_ISO );
return ( m.titles().get( us ) );
}
private String getRTId( Movie m ) {
return ( m.externalIds().get( ExternalMovieRepository.ROTTEN_TOMATOES ) );
}
private Map<Country, String> findByUSTitle( String usTitle ) {
// call some collaborating object
}
private Map<Country, String> findByRTid( String rtId ) {
// call some collaborating object
}
}
Could this design be improved?