1

Before I jump into the meat of the question, let me note that this is a purely theoretical query. I'm not interested in this for practical reasons, I'm interested in the underlying OOP theory on how to handle this type of situation.

In a project I'm working on, I have two closely related classes. One is the generic 'user' class. The other is subclassed, and adds additional features used by certain users -- for a generic example, think a 'moderator' class.

How do I handle public methods that are available on the user class that don't make sense for the child to have called?

For example, it makes perfect sense to call User::getUserWithId(id) (this method retrieves data from the DB and initializes and returns the user class with that data); it doesn't make as much sense (if any) to use that method with the moderator class.

Should I just ignore it -- if a user calls moderator::getUserWithId(id), they're still getting a user, exactly what they asked for. Should I override it to return a moderator, despite the method name? Or is there something in OOP land I'm not familiar with that lets me 'block' the call?

Joe Alfano
  • 10,149
  • 6
  • 29
  • 40
RonLugge
  • 5,086
  • 5
  • 33
  • 61
  • 1
    is this helpful? http://stackoverflow.com/questions/5486402/disabling-inherited-method-on-derived-class –  Jan 21 '13 at 20:42
  • @MattyF actually yes, it is. I kinda figured there was a flaw in how I was conceptualizing the whole thing, because 'blocking' methods simply doesn't make sense... Now I just have to figure out what on earth I would name the superclass that both classes derive from. – RonLugge Jan 21 '13 at 20:46
  • 1
    UserAbstractBaseClass or UserABC – Ray Tayek Jan 21 '13 at 20:50

2 Answers2

1

If you have methods in your base class that don't make sense in your subclass, then I think you need to re-evaluate if you should model these classes via an inheritance relationship. Needing to hide members of a base class in a subclass is a red flag that indicates modeling this via an inheritance relationship is problematic.

An inheritance relationship should indicate an "is a" relationship. For your example, a moderator object "is a" user object and thus should have the same methods and properties as the user object. If it does not, then it would appear that it does not have a true inheritance relationship with its base user class.

In this case, you might want to consider using interfaces instead of inheritance. You can factor the common functionality between the User and Moderator classes into an interface. If there is common code that they can share, then you can use composition to achieve this, by creating a common implementation of the interface and then passing it to the classes that need to reuse this code. For further information, see here and here.

As the author in the second link above puts it:

  • Does TypeB want to expose the complete interface (all public methods no less) of TypeA such that TypeB can be used where TypeA is expected? Indicates Inheritance.

  • Does TypeB only want only some/part of the behavior exposed by TypeA? Indicates need for Composition.

From your need to hide a member of the base class, it seems that you are in the second category, and might want to explore using composition and an interface.

Community
  • 1
  • 1
Joe Alfano
  • 10,149
  • 6
  • 29
  • 40
  • Thanks, good way to explain it. The irony is that moderators are DEFINITELY a 'type of' user; it's just that in this case, the 'subclass' has additional properties (and associated methods) that need to be set by the getter. – RonLugge Jan 22 '13 at 03:33
1

Yesterday I left a response, that somehow got lost. I think, @Joe Alfano has a very good explanation that addresses your "theoretical" and also particular questions. Beside that, In my opinion, one source of your problem might be that you are doing database access in your Domain Object. In general, unless there is a compelling reason, this is not a good practice. If you remove that database access into a separate layer like Data Access Layer (DAL) this problem goes away. You won't have User::getUserWithId(id) things in your classes, they will be handled in DAL. Like

class UserDao {
     User getById(id)

}

Class ModeratorDao {

     Moderator getById(id)
}

If you go with DAL-like approach, then you will also find ways to re-factoring code, which is a separate thing.

Nazar Merza
  • 3,365
  • 1
  • 19
  • 19
  • Well, more research for me. Thanks... I always love learning :D – RonLugge Jan 22 '13 at 19:36
  • Thank you again for this little tidbit... I've been trying to work out how to unit test against classes that do things in the DB, and I think that DAL might be the key. The only 'issue' such as it is will be 'test' cases where my 'live' case needs to automatically and internally sync to the DB... and I suspect that eventually I can come up with ideas to work around that. So you've solved two birds with one stone here -- and those are pretty major birds that WILL help solve more birds. So... thanks. A LOT! – RonLugge Jan 25 '13 at 17:52