The fragile base class problem

Another problem with implementation inheritance is that changes to the base class (parent class) can possibly break functionalities of its subclasses. From the earlier Java example, we have a CountingBag class that extends from the Bag class. Let's look at the complete source code, including the main function:

The program simply creates a CountingBag object. Then it adds apple using the add method and adds banana and orange using the addMany method. Finally, it prints out the items in the bag and the size of the bag. The output is shown in the following code:

Everything looks fine at the moment. But let's say that the original author of Bag realizes that the addMany method can be improved by directly adding objects into the items array list:

Unfortunately, this seemingly safe change in the parent class ends up in a disaster for CountingBag:

What happened? When CountingBag was designed, it was assumed that the add method would always be called when new items are added to the bag. When the addMany method stops calling the add method, the assumption no longer applies.

Whose fault is this? Of course, the designer of the Bag class cannot foresee who will inherit the class. The change in the addMany method did not violate any contract; the same functionality is provided, only with a different implementation under the hood. The designer of the CountingBag class thought it was wise to tag along and leverage the fact that addMany was already calling the add method, and so only the add method needed to be overridden to make counting work.

This poses a second issue with implementation inheritance. The subclass developer has too much knowledge about the implementation of the parent class. The ability to override the parent class's add method has also violated the principle of encapsulation.

How does OOP solve this problem? In Java, there are multiple facilities to prevent the problem presented in the preceding example:

  • A method can be annotated with the final keyword to prevent the subclass from overriding the method.
  • A field can be annotated with the private keyword to prevent the subclass from accessing the field.

The trouble is that the developer must anticipate how classes are going to be inherited in the future. Methods must be carefully examined to determine whether it is safe to allow subclasses to access or override. Likewise for fields. As you can see, the problem is called the fragile base class problem for a good reason.

I hope we have shown you that implementation inheritance does more harm than good. For reference, in the GoF design patterns book, it was also suggested that composition is preferred over inheritance. Julia took a more radical approach by just disallowing implementation inheritance altogether.

Next, we will go a little further and look at a specific kind of behavior subtyping called duck typing.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.213.209