Peter said:
Neither of those things changes the "has a" relationship between a car
and an engine. If those things would affect the inheritance relationship
between classes, the design would be very unstable when new requirements
need to be implemented. My experience is that a good design rarely needs
to be changed if at all. If the requirements change one might need to
add classes or members here and there, but it should not affect the
inheritance tree of existing classes.
You make an excellent point regarding design which I have seen very few
engineers cite. New requirements should have little impact on a design.
The design quandary for software is that you don't allways know what
these features might be. The cost of maintaining a software product is
often directly related to this often overlooked factor.
More to the point, until you know the design requirements, you have NO
idea what you are designing for and what guesses you're making for these
unknown features.
Since the terms "Car" and "Engine" classes has little or no bearing to a
real physical car and engine, and you have no idea what features you are
optimizing for you should not prejudice your decision making by
assuming anything - including inheritance models.
Design Rule 1 - never artificially limit the utility of a class.
Arbitrary prejudice inevitably leeds to limited class utility and hence
poorer design.
You might be right, you may never need or want to subclass off an
"engine" class. The problem I have is that in a design process, the
decisions regarding class design appear after considering all design
requirements as well as the best guesses on new features you can come up
with. It is a flaw to make significant design decisions too early in
the process. Considering no design goals and stating that "car -has-a-
engine" is quite clearly a mistake because you limit the solution space
artificially.
One property of inheritance is that the base class interfaces are
available on the derived class and hence any change in the base class is
reflected on the derived class. When considering a design, this is the
predominant factor. The is-a vs has-a nonsense is simply a guideline to
help less experienced designers make a good decision. A more
experienced designer will seldom use the is-a vs has-a paradigm and will
instead optimize the design so that as new features are added, the
"right thing" happens with fewer chances of error. The "right thing"
often is somthing far more subjective since it depends on whose crystal
ball you are peering through.