8
\$\begingroup\$

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 externalIds 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?

\$\endgroup\$

1 Answer 1

7
\$\begingroup\$

One thing - this design is based on a false premise - that there is only ever a single title within a given country. See for example this movie which has 3 USA titles (albeit only one, final, official title). This can be fixed by changing the Country key of the hash map to a TitleType (which will often be just a country).

Another problem is that Movie isn't really an object - it doesn't implement any member functions. In fact, your RottenTomatoesTitleFinder works by directly manipulating Movie properties rather than calling Movie member functions. This is a violation of basic OO principles.

\$\endgroup\$
2
  • \$\begingroup\$ Good point abouth the non-uniqueness of titles. I have added the accessors. Since I don't use the getX convention, I should have typed them out before. But I suppose that encapsulation is still breached the same as the Movie class just hands over its internals (the two maps). \$\endgroup\$
    – brabec
    Commented Aug 23, 2012 at 18:46
  • 1
    \$\begingroup\$ @stoupa - Instead of returning the maps, provide accessors such as Movie.getTitle(Country). \$\endgroup\$ Commented Aug 23, 2012 at 19:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.