I'm looking for a design pattern or convention to decouple services that handle owned entities. Let's say I have a ThemeService
, which handles creating Themes. At first, ThemeService
just persists Themes for each user's UserData
, but requirements change and Themes are owned by other entities, like a ThemeCollection
. My problem is, each ThemeService
is tightly coupled to whatever their "owning" entity is. For example:
public class ThemeService{
//coupled to UserData
createTheme(Theme t, UserData u);
getTheme(String name, UserData u);
hasTheme(String name, Userdata u); //Theme name unique within a userdata.
validateTheme(Theme t, UserData u); //unique name per user, valid colors, etc.
}
public class UserDataService{
ThemeService tService; //component for themes
getUsername(UserData u);
addTheme(Theme t, UserData u){ tService.createTheme(t, u); }
getTheme(String name, UserData u){ tService.getTheme(name, u); }
hasThemes(String name, UserData u){ tService.hasTheme(name, u); }
}
Now ThemeService is tightly coupled to the UserData. If requirements ever change and Themes can belong to another entity, ThemeCollection for example, then I can't really re-use much of the code from the ThemeService, and now need more code for ThemeCollection stuff:
public class ThemeService{
//...continued or in another ThemeService class...
createTheme(Theme t, ThemeCollection c);
getTheme(String name, ThemeCollection c);
hasTheme(String name, ThemeCollection c);
validateTheme(Theme t, ThemeCollection c);
}
public class ThemeCollectionService{
ThemeService tService;
getCollectionName(ThemeCollection c);
addTheme(Theme t, ThemeCollection c){ tService.createTheme(t, c); }
getTheme(String name, ThemeCollection c){ tService.getTheme(name, c); }
hasThemes(String name, ThemeCollection c){ tService.hasTheme(name, c); }
}
I would be tempted to make it take a generic parameter that implements something like "Themeable." However, that would make the entities implement an interface:
public class ThemeService{
createTheme(Theme t, Themeable owner);
getTheme(String name, Themeable owner);
hasTheme(String name, Themeable owner);
validateTheme(Theme t, Themeable owner);
}
@Entity
public class UserData implements Themeable{
getUsername();
getThemes(); //From Themable
}
@Entity
public class ThemeCollection implements Themeable{
getUsername();
getThemes(); //From Themable
}
I don't include the create, get, validate, etc. in the Themeable interface because I don't want business logic in my entity classes which should hopefully be a pure data structure (having business logic in the model is sloppy according to Robert Martin's "Clean Code", and I'm trying to follow some standard).
Is there a standard way, pattern, convention, etc., to decouple this? Is what I have more or less "okay" or is it frowned upon in a production environment? I'm trying to get away from code that "gets the job done" and towards modular and reusable code, so any help and pointers are greatly appreciated.
Edit: "Why are your services coupled to two entities?"
I need a place to 'stitch' the owning entity and the owned entities together. For example, createTheme for a UserData:
public void createTheme(Theme t, UserData u){
entityManager.persist(t);
if(!hasTheme(t.name(), u){
u.getThemes().add(t);
entityManager.merge(u);
}
}
So this function is coupled to UserData, and any similar "Theme Owners" would have similar code.