OO Design - Separating Instance-specific functions

2019-08-04 08:56发布

问题:

Given a class that is semantically supposed to be an object of a certain type, but also has multiple operations for operating on objects of its own type, what is the best way(pattern?) of organizing the class in this type of scenario? I find this to be a common occurrence when a developer creates objects but is thinking with a procedural mindset.

Example:

Class User {
  private m_userData;
  function User() {}
  function GetUserData() {}

  function KillAllUsers(){}
  function MaimAllUsers(){}
}

回答1:

It's not very clear from your description, but it seems that the "KillAllUsers" and "MainAllUsers" methods are operating on a set of users. I would recommend creating a custom UserCollection that has these methods as instance methods or create them as statics and pass in a collection of users. In modern domain model terms, you'd be dealing with a UserRepository.



回答2:

I'd rather tend to separate these two purposes into a User and a UserManager class. IMO this provides a clearer separation of what the classes are supposed to do.

Edit: As Dunk correctly observed, the actual name in your application should not be UserManager, but something more descriptive of it's actual purpose. Often times you'll find a design pattern for the functionality you are going to use, so the name of the class will be provided by that pattern. This might lead to names such as UserRepository or UserFactory.



回答3:

Make an abstraction of the operations you want to perform on your objects, for example by creating an interface. Then you can worry later on how to provide the implementation of the actual logic.

Usually, when dealing with collections of objects of, say, type User, it will not be User itself that will implement it, but another object like UserService for example. If absolutely want it to be available on the class level, you can define a static method that returns the interface type and a default implementation.



回答4:

methods like killAllUsers() or MaimAllUsers() is only encapsulating the intended operation the "what", its incomplete information in terms of the interaction specifically the "who". You can .kill() or .maim() a User instance, but there needs to be somebody(JackTheReaper) who intends to do that to the User, hence the kill() and maim() are interactions between JackTheReaper and User, the part of the intention that is expressed by "All" in killAllUsers() is a responsibility of JackTheReaper class of how it manages reference of all users. Essentially the trick here is abstract away type level functionalities as interaction b/w the entities