October 30, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Encapsulation vs. Inheritance

  • August 4, 2005
  • By Matt Weisfeld
  • Send Email »
  • More Articles »

How Inheritance Weakens Encapsulation

As already stated, encapsulation is the process of packaging classes into the public interface and the private implementation. In essence, a class hides everything that is not necessary for other classes to know about.

Peter Coad and Mark Mayfield make a case that, when using inheritance, encapsulation is inherently weakened within a class hierarchy. They discuss a specific risk: Inheritance indicates strong encapsulation with other classes, but weak encapsulation between a superclass and its subclasses.

The problem is that if you inherit an implementation from a superclass and then change that implementation, the change ripples through the class hierarchy. This rippling effect potentially affects all the subclasses. At first, this might not seem like a major problem; however, as you have seen, a rippling effect such as this can cause unanticipated problems. For example, testing can become a nightmare. In earlier columns, you covered how encapsulation makes testing systems significantly easier. In theory, if you create a class called Cabbie (see Figure 2) with the appropriate public interfaces, any change to the implementation of Cabbie should be transparent to all other classes. If the other classes were directly dependent on the implementation of the Cabbie class, testing would become more difficult, if not untenable.

Note: Even with encapsulation, you would still want to retest the classes that use Cabbie to verify that no problem has been introduced by the change.

Figure 2: A UML diagram of the Cabbie class.

If you then create a subclass of Cabbie called PartTimeCabbie, and PartTimeCabbie inherits the implementation from Cabbie, changing the implementation of Cabbie directly affects the PartTimeCabbie class.

For example, consider the UML diagram in Figure 3. PartTimeCabbie is a subclass of Cabbie. Thus, PartTimeCabbie inherits the public implementation of Cabbie, including the method giveDirections(). If the method giveDirections() is changed in Cabbie, it will have a direct impact on PartTimeCabbie and any other classes that might later be subclasses of Cabbie. In this subtle way, changes to the implementation of Cabbie are not necessarily encapsulated within the Cabbie class.

Figure 3: A UML diagram of the Cabbie/PartTimeCabbie classes.

To reduce the risk posed by this dilemma, it is important that you stick to the strict is-a condition when using inheritance. If the subclass were truly a specialization of the superclass, changes to the parent would likely affect the child in ways that are natural and expected. To illustrate, if a Circle class inherits implementation from a Shape class, and a change to the implementation of Shape breaks Circle, then Circle was not truly a Shape to begin with.

How can inheritance be used improperly? Consider a situation in which you want to create a window for the purposes of a graphical user interface (GUI). One impulse might be to create a window by making it a subclass of a rectangle class:

class Rectangle {
}
class Window extends Rectangle {
}

Listing 1

In reality, a GUI window is much, much more than a rectangle. It is not really a specialized version of a rectangle, as is a square. A true window might contain a rectangle (in fact, many rectangles); however, it is really not a true rectangle. In this approach, a Window class should not inherit from Rectangle, but it should contain Rectangle classes.

class Window {
   Rectangle menubar;
   Rectangle statusbar;
   Rectangle mainview;
}

Listing 2





Page 2 of 4



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel