HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Java API without exposing implementation details

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
withoutexposingjavadetailsimplementationapi

Problem

I am creating an API for consumption by other developers to interface with an internal framework. My goal is to be able to have the developers type something like:

profile.setPreference(new GroupPreference(id));


or

UserPreference preference = new UserPreference();
preference.setDefaultInbox("nameOfInbox");
// set any other options, classes simplified
profile.setPreference(preference);


The internal framework has all preferences persisted in the same manner. A user profile can be either a set of preferences specific to them (UserPreference) or a relation to a group preference using an ID (GroupPreference).
An example of current API usage:

// Context object 
Profile profile = userService.getProfile("accountName");

// Preference returned here is immutable
Preference preference = profile.getPreference();
preference.getDashboardOptions();
preference.getDefaultInbox();
// etc..

// To modify a users preferences
UserPreference userPreference = new UserPreference(preference);
userPreference.setDefaultInbox("newInbox");
// etc..

profile.setPreference(userPreference);

// Or to link it to a group preference
profile.setPreference(new GroupPreference(groupPreferenceId));


I handle saving of the preference information through a PreferenceManager as a part of updating the overall profile:

preferenceManager.savePreference(preference, profileContext);


Now for the questions:

  • The protected save method feels extremely cludgy but I didn't want to have any methods in the interface that potentially exposes implementation details. Is there a better way?



  • How is this design overall? Something need to be reorganized?



```
public abstract class Preference {
/**
* Provides access to DashboardOptions object to manage what options are enabled
* and disabled on the users dashboard.
*
* @return DashboardOptions object
*/
public abstract DashboardOptions getDashboardOptions();
/**
* Gets the default inbox f

Solution

Your Preference class really looks like it should be an interface. And in fact it is actually two interfaces: The public one for the user and the internal one for the manager. So I'd suggest you split it up:

public interface Preference {
    /**
     * Provides access to DashboardOptions object to manage what options are enabled
     * and disabled on the users dashboard.
     * 
     * @return DashboardOptions object
     */
    DashboardOptions getDashboardOptions();

    /**
     * Gets the default inbox for the user.
     * 
     * @return Default inbox
     */
    String getDefaultInbox();
}

interface SaveablePreference extends Preference  // package private
{
    /**
     * Method that will be overridden to handle saving of the preference.
     * 
     * @param profile ProfileContext passed in to provide information when saving preferences
     * @param service PreferenceService object that handles saving of preferences
     */
    void save(ProfileContext profile, PreferenceService service);
}


Your users will only ever get the Preference but your implementations (UserPreference and GroupPreference) will implement SaveablePreference.

Update

Looking at it again it don't really see the point of the PreferenceManager. If the user will have to call the manager in order to save the preference then why don't make the save method public in the first place - so you end up with only one interface. Then the user can call preference.save(context, service) (the arguments he'd have to supply anyway when calling the manager).

Code Snippets

public interface Preference {
    /**
     * Provides access to DashboardOptions object to manage what options are enabled
     * and disabled on the users dashboard.
     * 
     * @return DashboardOptions object
     */
    DashboardOptions getDashboardOptions();

    /**
     * Gets the default inbox for the user.
     * 
     * @return Default inbox
     */
    String getDefaultInbox();
}

interface SaveablePreference extends Preference  // package private
{
    /**
     * Method that will be overridden to handle saving of the preference.
     * 
     * @param profile ProfileContext passed in to provide information when saving preferences
     * @param service PreferenceService object that handles saving of preferences
     */
    void save(ProfileContext profile, PreferenceService service);
}

Context

StackExchange Code Review Q#39982, answer score: 4

Revisions (0)

No revisions yet.