Thursday, October 20, 2005

More on Composition versus Inheritance

Is there any more basic OO design decision than this? I started off, like many newer OO programmers, writing code with a lot of concrete inheritance. After some painful lessons and more reading, I now lean heavily toward using composition. So OK. How do we nail down exactly when to use which approach?

Bill Venners writes about this in JavaWorld
. The key criteria to consider is whether the relationship is really an “is-a” relationship, and just how strong the is-a is.

Make sure inheritance models the is-a relationship [...]

An important question to ask yourself when you think you have an is-a relationship is whether that is-a relationship will be constant throughout the lifetime of the application and, with luck, the lifecycle of the code. For example, you might think that an Employee is-a Person, when really Employee represents a role that a Person plays part of the time. What if the person becomes unemployed? What if the person is both an Employee and a Supervisor? Such impermanent is-a relationships should usually be modeled with composition.


He continues to point out that both code-reuse and polymorphism can be achieved with composition, and should not be a reason to use inheritance without a strong is-a relationship.

java.net hosts a discussion on the topic. A common approach is to code using interfaces, and use concrete inheritance in the implementations--in other words, use composition (with interfaces) in your design, use inheritance (for re-use or polymorphism) in the implementation. The is-a rule would still apply to the implementations, of course.

Friday, October 14, 2005

OO Design Principles: a Quick Rundown

I wanted to collect some good resources on basic OO design principles, with brief summaries of each, so that I have everything in one place. I hope to ultimately distill these into a one-page "crib sheet.'

Some of the best wisdom in OO design is captured by the Gang of Four. Artima has an interview with Erich Gamma where he discusses the core principles from the intro of Design Patterns:

Program to an Interface, not an Implementation

Once you depend on interfaces only, you're decoupled from the implementation. That means the implementation can vary, and that's a healthy dependency relationship.

Rod Johnson expands on this idea in Chapter 4 of the pre-Spring book, and provides some very well-phrased guidelines:

Program to interfaces, not classes. This decouples interfaces from their implementations. Using loose coupling between objects promotes flexibility.

...

A few of the many advantages of an interface-based approach include:

  • The ability to change the implementing class of any application object without affecting calling code. This enables us to parameterize any part of an application without breaking other components.
  • Total freedom in implementing interfaces. There's no need to commit to an inheritance hierarchy. However, it's still possible to achieve code reuse by using concrete inheritance in interface implementations.
  • The ability to provide simple test implementations and stub implementations...

Turning back to the Gamma interview...

Favor object composition over class inheritance

Composition has a nicer property. The coupling is reduced by just having some smaller things you plug into something bigger... In a subclass you can make assumptions about the internal state of the superclass when the method you override is getting called. When you just plug in some behavior, then it's simpler. That's why you should favor composition.

Mr. Johnson expands:

To clarify the distinction, let's consider what we want to achieve by inheritance. Abstract inheritance enables polymorphism: the substitutability of objects with the same interface at run time. This delivers much of the value of object-oriented design... Concrete inheritance enables both polymorphism and more convenient implementation.

...Interface inheritance (that is, the implementation of interfaces, rather than inheritance of functionality from concrete classes) is much more flexible than concrete inheritance.

Robert Martin is another thought leader on core principles, has defined several core principles including the following:

[NOTE: Still under development]

The Single Responsibility Principle (SRP)

There should never be more than a single reason to change a class... Changes to one responsibility may impact other responsibilities.

Open Closed Principle (OCP)

A module should be open for extension but closed for modification

Should be able to add behavior without modifying common behavior

Liskov Substitution Principle (LSV)

Subclasses should be substitutable for their base classes

The Interface Segregation Principle (ISP)

Interfaces shouldn't have stuff that their clients don't need... Factor interfaces so that clients can use just relevant members

The Law of Demeter

Only talk to your friends who share your concerns... Never call a method on an object that you got from another call or on a global object.

http://c2.com/cgi/wiki?LawOfDemeter

http://www.ccs.neu.edu/home/lieber/LoD.html

http://c2.com/cgi/wiki?LawOfDemeterRevisited

The Dependency Inversion Principle

Modules should depend on abstractions, not concrete modules... Details [controllers?] should depend on abstractions, not the other way around.

"Inversion" in contrast to structured, procedural thinking.

Monday, October 10, 2005

Garbage Collection is still important

I think in J2EE, it is easy to get away from the basics of solid Java programming, assuming that the container will take care of the hard stuff for us. Understanding how GC works, however, can be crucial for J2EE applications, expecially high volume or long running runs. I don't know about you, but I might need to brush up on this stuff.

Simon Roberts delivered a great primer on the topic to the DJUG Architecture SIG last week, we'll try to get slides up on the archive soon.