In the Beginning...

Mantras Considered Harmful

Definitions

Class: a named concept in the domain space, with an optional superclass, defined as a set of fields and methods.

Field: a named property of some type, which may reference another object (see composition)

Method: a named function or procedure, with or without parameters, that implements some behavior for a class.

Inheritance: a class may inherit - use by default - the fields and methods of its superclass. Inheritance is transitive, so a class may inherit from another class which inherits from another class, and so on, up to a base class (typically Object, possibly implicit/absent). Subclasses may override some methods and/or fields to alter the default behavior.

Composition: when a Field’s type is a class, the field will hold a reference to another object, thus creating an association relationship between them. Without getting into the nuances of the difference between simple association, aggregation, and composition, let’s intuitively define composition as when the class uses another object to provide some or all of its functionality.

Encapsulation: by interacting with objects instead of directly with the implementation of methods and fields, we hide and protect the implementation of a class. If a consumer does not know anything about an object other than its public interface, then it cannot rely on any internal implementation details.

Inheritance is Fundamental

…and so is Composition

So What’s the Fuss About?

Inheritance Semantics

Inheritance Mechanics

How to Misuse Inheritance - Example 1

class Stack extends ArrayList { public void push(Object value) { … } public Object pop() { … } }

Semantically, the statement “a Stack is an ArrayList” is not true; Stack is not a proper subtype of ArrayList. A stack is supposed to enforce last-in-first-out, a constraint easily satisfied by the push/pop interface, but not enforced by ArrayList’s interface. Mechanically, inheriting from ArrayList violates encapsulation; using ArrayList to hold the stack’s object collection is an implementation choice that should be hidden from consumers. Finally, implementing a Stack by inheriting from ArrayList is a cross-domain relationship: ArrayList is a randomly-accessible Collection; Stack is a queuing concept, with specifically restricted (non-random) access8. These are different modeling domains.

How to Misuse Inheritance - Example 2

ArrayList<Customer> is a subclass of list already, a utility collection - an implementation class. CustomerGroup is another subclass - a domain class. Domain classes should use implementation classes, not inherit from them.

Single Inheritance is not the Problem

Unless you are creating an implementation class, you should not inherit from an implementation class.

Using Inheritance Well

How to Decide: Composition or Inheritance?

The representation/implementation of your domain concepts is one dimension The semantics of your domain concepts and their relationship to one another is a second dimension

Both classes are in the same logical domain The subclass is a proper subtype of the superclass The superclass’s implementation is necessary or appropriate for the subclass The enhancements made by the subclass are primarily additive.

Higher-level domain modeling

Frameworks and framework extensions

Differential programming

Appendix



systems and applications programmers adopted C++ in the mid 1980s, but OOP ubiquity had to

yes, I’m oversimplifying, ignoring listeners/event delegates/etc.; trying to keep this article short!

Amazon claims 24,777 books on the topic of object-oriented programming as of this writing

Google search claims ~8M results for the exact phrase “object-oriented programming” as of this writing

Google search yields an estimated 37,600 results for the exact phrase “inheritance is evil” as of this writing

Semantics (interfaces) and mechanics (representation) could be separated, at the cost of additional language complexity; see for example the

Note with some sadness that Java’s Stack class inherits from Vector.

Designing classes for reuse via inheritance is beyond the scope of this article. Just keep in mind that consumers of instances and subclasses have different needs, both of which must be satisfied by your class design. 1 . The first officially object-oriented language, SIMULA 67, was born in 1967. Object-oriented programming is 48 years old! 2. systems and applications programmers adopted C++ in the mid 1980s, but OOP ubiquity had to wait another decade 3. yes, I’m oversimplifying, ignoring listeners/event delegates/etc.; trying to keep this article short! 4. Amazon claims 24,777 books on the topic of object-oriented programming as of this writing 5. Google search claims ~8M results for the exact phrase “object-oriented programming” as of this writing 6. Google search yields an estimated 37,600 results for the exact phrase “inheritance is evil” as of this writing 7. Semantics (interfaces) and mechanics (representation) could be separated, at the cost of additional language complexity; see for example the D language specification by C. J. Date and Hugh Darwen. 8. Note with some sadness that Java’s Stack class inherits from Vector. 9. Designing classes for reuse via inheritance is beyond the scope of this article. Just keep in mind that consumers of instances and subclasses have different needs, both of which must be satisfied by your class design.