Java – how to organize OO design using two different types of users
I have two different types of users. I map them to two Java classes userwheel and usersea, which have a public abstract superclass named user The data saved for these user types is roughly the same, but the behavior is different
Then I created an abstract class named usercollection, whose derived classes userwheelcollection and userseacollection are used to search for or load sub users
Then I added an abstract method of the signed usercollection class
public abstract List<User> listAllSubusers()
This is because the implementation will be different Each user created will be userwheel or usersea, depending on the method invoked, but the rest of the implementation is completely different
Then I want to add a new method to the usercollection with the signature public user loadbyid (int iduser) In this case, the implementation will be the same, except that the fact returned by the user will be an instance of userwheel or usersea In this case, I don't want to use abstract methods in the base class because the code is repetitive
I can use instanceof to check the concrete class of usercollection and create an appropriate subclass, but it doesn't seem object-oriented and breaks the open principle
Another idea is to add an abstract method createnewuser() to the usercollection and add a concrete implementation in the subclass to return a new instance, so the base class will only call this createnewuser() method
Do you think the second way is meaningful? Or will you organize things in different ways and how?
UPDATE. The current situation is:
abstract class User public String getAddress() public void setAddress() ... class UserSea extends User class UserWheel extends User abstract class UserCollection protected abstract User createNewUser(); public abstract List<User> listAllSubUsers(); public User loadById(int idUser) { User newUser = createNewUser(); //populate it return newUser; } class UserSeaCollection protected User createNewUser() { return new UserSea(); } public List<User> listAllSubusers() class UserWheelCollection protected User createNewUser() { return new UserWheel(); } public List<User> listAllSubusers()
I try to understand the strategy pattern suggested by trashgod. This is my first attempt:
interface SubuserManagement List<User> listAllSubUsers(); ... interface UserCrud void create(); User readById(int idUser); void update(); void delete(); class UserSeaCollection implements SubUserManagement,UserCrud private SubUserManagement subuserBehavior = new SubUserManagementSeaImplementation(); private UserCrud userCrudBehavior = new UserCrud(); void create { subUserBehavior.create(); } ... class UserWheelCollection implements SubUserManagement,UserCrud ... class SubUserManagementWheelImplementation implements SubUserManagement List<User> listAllSubUsers(); class SubUserManagementSeaImplementation implements SubUserManagement List<User> listAllSubUsers(); class UserCrudImplementation implements UserCrud //only 1 implementation void create(); User readById(int idUser); void update(); void delete();
In my first attempt, I created usercollectionwheel and usercollectionsea, which no longer share a public superclass, but implement the same interface The actual implementation is in an external class
Now usercollectionwheel and usercollectionsea are actually the same class, the only difference is the behavior I assign to them Or, I can only write one class with setter:
UserCollection userColl = new UserCollection(); userColl.setSubUserBehavior(new SubUserManagementSeaImplementation()); userColl.setCrudBehavior(new UserCrud());
But initialization can be cumbersome, especially if I have more behavior classes So what did I do wrong? How to organize properly?
Update 2: I wrote a blog post with the design I implemented
Solution
Instead of inheriting behavior, consider encapsulating it with an interface in strategy pattern Users will be different when using interface listsubusersstrategy and interface createuserstrategy
See also the related bridge pattern
Appendix: in the following example, each user has a specific strategy to find sub users In particular, listallsubusers () calls the interface method and is automatically dispatched to the correct concrete implementation This pattern does not relieve you of writing concrete implementations of interfaces, but it does decouple them and ensure that changing it does not destroy another
Comfort:
A has wheel users. B has sea users. C has wheel users.
Code:
import java.util.ArrayList; import java.util.List; /** @see https://stackoverflow.com/questions/6006323 */ public class UserMain { private static final List<User> users = new ArrayList<User>(); public static void main(String[] args) { users.add(new User("A",new WheelStrategy())); users.add(new User("B",new SeaStrategy())); users.add(new User("C",new WheelStrategy())); for (User user : users) { user.listAllSubUsers(); } } private static class User { private String name; private SubUseRSStrategy suStrategy; public User(String name,SubUseRSStrategy suStrategy) { this.name = name; this.suStrategy = suStrategy; } public void listAllSubUsers() { System.out.print(name + " manages "); List<User> subUsers = suStrategy.getList(); } } private interface SubUseRSStrategy { List<User> getList(); } private static class WheelStrategy implements SubUseRSStrategy { @Override public List<User> getList() { System.out.println("wheel users."); return null; } } private static class SeaStrategy implements SubUseRSStrategy { @Override public List<User> getList() { System.out.println("sea users."); return null; } } }