1

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(){}
}
Adam Bellaire
  • 108,003
  • 19
  • 148
  • 163
Dewayne
  • 3,682
  • 3
  • 25
  • 23

4 Answers4

4

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.

Christophe Herreman
  • 15,895
  • 9
  • 58
  • 86
4

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.

Adrian Grigore
  • 33,034
  • 36
  • 130
  • 210
  • Not sure if I'd call it "UserManager" but it makes sense that the code that is creating these users is responsible for killing/maiming them. – Tim Frey Feb 17 '09 at 19:57
  • The manager class wouldn't *have* to be a creation factory... If you want to enforce just a single user manager per application (which can be legitimate) then have User have a set of static functions is reasonable too. – Jeff Kotula Feb 17 '09 at 21:02
  • Please remove the word manager from your vocabulary when talking about class names. The name of the class should be descriptive of its' purpose. Manager is just another word for *dumping ground*. Any functionality will fit there. The word has been the cause of many extremely bad designs – Dunk Feb 17 '09 at 22:49
  • Dunk: I agree that usermanager is not very descriptive, but I chose this name because I could not see any design pattern that fits the two functions KillAllUsers and MaimAllUsers (a Repository does not maim...). Perhaps Dewayne needs in fact a factory class, in which case it would be a UserFactory. – Adrian Grigore Feb 18 '09 at 07:46
1

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.

eljenso
  • 16,789
  • 6
  • 57
  • 63
  • Not sure where you're going with the part about creating an interface. That's not going to choose between making a static method in User or putting it someplace else. – Tim Frey Feb 17 '09 at 20:00
  • The choice is very clear: don't do it using static methods on User. Put is somewhere else. If you do want it on User as some kind of static, it's better to have a static getUserService method on User that returns the interface type and a default implementation. – eljenso Feb 17 '09 at 20:13
0

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

redzedi
  • 1,957
  • 21
  • 31