When subclassing an object, what is the appropriate method to handle functions that don't make sense on the child?

StackOverflow https://stackoverflow.com/questions/14446820

Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top