A long running debate in the OO community is the IsA/HasA debate.

The question can be summarised: If I have a class X, and I want to use features of class Y, should I create X subclasses Y or should I have X has an instance of Y instead? It's also known as the IsA/HasA question, because the question is whether X is a Y or X has a Y.

Developers that are new to OO will simply create a subclass (and go down the is-a path) because they've been taught that subclassing inherits functionality, and thus you can inherit the features that you want. Indeed, implementations in Java (such as Stack subclassing Vector) are an example of this subclassing in operation.

The problem with the is-a approach is that not only do you end up inheriting the methods (desired result), you also end up inheriting its type (undesired result). The goal of polymorphism (subclassing to you and me) is that it should provide substitutability; that is, you should be able to treat all types of Y as being the same kind of thing.


Examples

Is a

public class Y {
{{{  public void doSomething() { ... } 
  public void doSomethingElse() { ... } 

} public class X extends Y { {{{ // inherits doSomething() and doSomethingElse()

}

Has a

public class Y {
{{{  public void doSomething() { ... } 

} public class X { {{{ private Y myY = new Y();

// not always required; in most cases, may not be {{{ public void doSomething() {

// may not want to delegate doSomethingElse() }


Note that an undesired effect of using the is-a approach is that you always inherit all of the methods, even if you only want one of them (or a subset). In some cases, this is positively undesirable since you may not want to expose some of your methods.

Case in point: Take the Stack and Vector example outlined above. Given that Stack is a subclass of Vector, it not only inherits the storage area (and methods for manipulating it) but it also inherits the other methods. This provides some useful methods (like <code>size()</code>) to be called, but also provides undesirable methods (like <code>get(int)</code>) which breaks the concept of a stack (you shouldn't be able to peek into the middle of the stack, nor remove elements from anywhere other than the top).

As such, Stack should have been implemented using the has-a instead of the is-a approach. That way, the Stack class provides exactly the methods required (and no more), but can still delegate functionality to the internal Vector as appropriate.

Another example: the JavaBean Property Change Support object, which provides methods to allow JavaBean objects to easily communicate with one another. Most uses of this (correctly) use the has-a approach, since the classes are generally not a type of PCS, but instead need to have an instance of PCS to 'do the dirty work' of JavaBean event firing.

Multiple versus single inheritance

One of the biggest (and briefest) complaints about Java is that it lacks multiple inheritance. Acutally, this is a Good Thing since multiple (implementation) inheritance generally causes more problems than it solves.

Using multiple inheritance makes it much easier to use is-a instead of has-a and introduce a number of problems (such as: if two superclasses Y1 and Y2 both have a method called <code>size()</code>, which one is inherited by subclass X?). A single inheritance model avoids those problems, and developers that correctly avoid the is-a solution don't worry.

(Actually, Java does have multiple inheritance; multiple interface inheritance. It just doesn't have multiple implementation inheritance, which is the bad thing.)

IsA/HasA (last edited 2009-09-20 23:32:06 by localhost)