#This is a real world problem I met. # #We have a database containing serveral tables, like : user, role, organization. Each 2 of them has m:n relationships. These relations are stored in association tables. # #Not we have to load all these data in memory to gain higher performances. We create 3 classes , User, Role, Organization, to hold these data. # #The question is : should I implement "add/delete/update" as methods of User, or should I add another class UserManager?
#---------------- # Choice 1 #---------------- user_dict = {} role_dict = {} class User: on_del_funcs = [] roles = [] def del(self): user_dict.pop(self.name) for f in self.on_del_funcs: f(self) # Using Observer Pattern to notify this user is deleted. def addUserDelListener(self, on_del_func): on_del_funcs.append(on_del_funcs) def delUserDelListener(self, on_del_func): on_del_funcs.remove(on_del_func) class Role: users = [] def addUsser(self, user): self.users.append(user) user.roles.append(self) users.addUserDelListener(self.onUserDel) def onUserDel(self, user): self.users.remove(user) user.delUserDelListener(self.onUserDel) #---------------- # Choice 2 #---------------- class UserManager: users = [] @classmethod def delUser(cls, user): cls.users.remove(user) RoleManager.onUserDel(user) class RoleManager: roles = [] @classmethod def onUserDel(cls, user): for r in cls.roles.items(): r.users.remove(user) # These codes are not complete, but that's enough to show my question. # The first choice, which use Observer Pattern, has a very big problem. # When calling addUserDelListener, user got not only a callback function, it # also add reference count of role. So when we want to delete a role. We have # to carefully remove all *listener* hold by other objects, otherwise this role # will never be garbage collected. # Not a big problem for only 2 classes. But when there are 10 *subject* classes which # Role want to *observe*, 10 listeners has to be removed when delete a role. # And if these *subject* have 5 different types of events, then 50 listeners has # to be removed. # Actually I tried this approach once, and it is still a big headache for 10 # programmers. ( The company I worked at that time hate any change to so-called # working code ) # The second choice, which I am using right now, actually has nothing to do with # Object Oriented Designing. The manager classes are not real classes, just # container of methods. These User/Role classes are only container of data, # not behavior. # # For many times, I asked my self, "Is it too hard for me to see the power of # OO, or I have just never met a problem suitable for a OO resolution?" -- http://mail.python.org/mailman/listinfo/python-list