Similar to InheritanceBreaksEncapsulation
. In this particular case the behavior of the subclass is dependent on the behavior of the superclass.
There are two types of fragile base class problem. The syntactic fragile base class problem
, which is described in FragileBinaryInterfaceProblem
, and the semantic fragile base class problem
, described here.
The semantic FragileBaseClassProblem
is when some dependency a client has on a child class would be broken by changing the base class thereof. Any language that allows any functionality from the parent to be invoked through an object of a derived class is susceptible to the FragileBaseClassProblem
As a simple example, assume you have a public method Foo() in class CBase. Assume that class CDerived derives from class CBase. Assume that some user (say, CUser) invokes Foo() on an instance of CDerived.
If you suddenly decided that Foo() wasn't needed, or needed a new name, or other arguments, changing Foo() in CBase would break CUser, even though CUser doesn't have an immediately obvious dependency on CBase.
This is especially a problem if you work with SharedLibraries?
and/or you are building a multi-component system, and not so much a problem if you build the entire system yourself, and it is a MonolithicSystem?
It is my understanding that the FragileBaseClassProblem
what is described at the top of the page, but the following:
Say that CDerived is a subclass from CBase and that CDerived has a method
bar(), which doesn't occur in CBase
. Now if CBase adds an unrelated method bar(), CDerived might break since it now overrides some arbitrary piece of the functionality in CBase. The same could also happen with instance variables instead of methods.
That wouldn't break anything if IntentionRevealingNames are used. Choosing the wrong names is of course a problem, but unrelated to the FragileBaseClassProblem.
Actually, introducing a new method to the base class which "underrides" a formerly non-overriding function in a derived class is fairly rare; though CsharpLanguage
provides the override keyword to prevent that sort of thing (and others).
The override is probably a case of WorseMedicineThanIllness?. If the base class and the derived class are created by different companies, it would be really hard to make any modification that doesn't break the build.
I don't understand this. Obviously if you delete a public method you will be affecting clients who call that method. And obviously if you are subclassing, the subclass is dependent on the implementation of the superclass; in fact, you even have special access to internal implementation details. Indeed, subclassing is extremely tight coupling. This is hardly a problem. This is the expectation of subclassing.
If you don't want to be dependent on the base class, use DelegationInheritance
instead of direct inheritance. But still, when the base class changes, the subclass will be necessarily (and thankfully) affected.
I think that is the whole point. A lot of times when delegation or interface inheritance should be used, people in the real world end up using implementation inheritance because 'it is more convenient' or 'to promote code reuse'. FragileBaseClassProblem
basically cautions us not to do that.
To not have this problem, base classes need to be 'real' classes that rise out of modeling exercises. In such (rare) cases, the base class apis and contracts can be clearly specified and change very infrequently. However, this seldom happens. Most of the times, people overuse implementation inheritance and end up with base classes that change all the time, often destabilizing their derived classes and perhaps, the entire system.
For example, if your program has two classes - Square and Circle, it is conceivable that you will create a Shape base class. That is probably fine, since Shape can be clearly defined (given the context). However, if you are developing a banking software for Foo bank and you have two classes - Customer and Account, you should resist the temptation to create a vague Foo base class simply because of misguided convenience.
Folks from academia might scoff; but this happens astonishingly often in business software. --SriramGopalan
Isn't the fragile base class problem better explained by the following example?
Having a base class defining an Add
method and an AddList
method which uses Add
, a derived class will override the Add
method to implement some specialization. Now, the previous functionality of AddList
in the base class is changed by using an optimized adding routine which doesn't depend on Add
anymore. The derived class will now show false results -- BernhardPollak