The preceding section summarized the application of object-oriented architectural techniques to the examples at hand. We must now examine the sketched result in light of the modularity criteria stated at the beginning of this discussion. The contribution to reliability follows from the type system and contracts; we concentrate on reusability and extendibility.
One of the principal consequences of using inheritance
is that common features can be moved to the highest applicable
level; then descendants do not need to repeat them: they simply
inherit them “as is.” If they do need to change the implementation
while retaining the functionality, they simply redefine (or
“override”) the inherited version. “Retaining the functionality”
means here that, as noted, the original contracts still apply,
whether the version being overridden was already effective or still
deferred. This goes well with dynamic binding: a client can use the
operation at the higher level—for example,
my_contract.value—without knowing what version of
the routine is used, in what class, and whether it is specific to
that class or inherited.
Thanks to commonalities captured by inheritance, the number of
feature definitions may be significantly smaller than the maximum
f. Any reduction here is valuable: it is a general rule of software design that repetition is always potentially harmful, as it implies future trouble in configuration ...