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 for the user.
*
* @return Default inbox
*/
public abstract String getDefaultInbox();
/**
* 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
*/
protected abstract void save(ProfileContext profile, PreferenceService service);
}
public class GroupPreference extends Preference {
private Long groupPreferenceId;
public GroupPreference(Long groupPreferenceId) {
this.groupPreferenceId = groupPreferenceId;
}
public Long getPreferenceId() {
return groupPreferenceId;
}
@Override
public DashboardOptions getDashboardOptions() {
return null;
}
@Override
public String getDefaultInbox() {
return null;
}
@Override
protected final void save(ProfileContext profile, PreferenceService service) {
service.setUserPreference(profile.getId(), groupPreferenceId);
}
}
public class UserPreference extends Preference {
private UserDashboardOptions options;
private String defaultInbox = "";
public UserPreference() {
this.options = new UserDashboardOptionsImpl();
}
public UserPreference(Preference preference) {
this.options = new UserDashboardOptionsImpl(preference.getDashboardOptions());
}
@Override
public UserDashboardOptions getDashboardOptions() {
return options;
}
@Override
public String getDefaultInbox() {
return defaultInbox;
}
public void setDefaultInbox(String defaultInbox) {
this.defaultInbox = defaultInbox;
}
@Override
protected final void save(ProfileContext profile, PreferenceService service) {
// The SubjectPreference is part of an internal framework I have to interface with
SubjectPreference subjectPreference = service.createSubjectPreference(profile);
service.saveSubjectPreference(subjectPreference);
}
}
public class PreferenceManager {
public void savePreference(Preference preference, ProfileContext profile, PreferenceService service) {
preference.save(profile, service);
}
}
Preference
should be an Interface instead of an Abstract class? \$\endgroup\$