Quick: if a square object inherits a rectangle object, what OO principle does this violate?
If your answer is Liskov Subsitution Principle (or Design by Contract principle), you can probably stop reading this now, since there is little new information for you below. If, however, you are having trouble thinking about OO principles beyond encapsulation, inheritance, and polymorphism (which, arguably, can be classified as both features and concepts of object orientation) and would like to learn a bit more, read on.
To paraphraze Dr. Dobb's Architecture Portal, "poor architectural design is everywhere; the brilliant designs are very rare." Obviously, lack of sufficient understanding of business processes is one major cause of poor systems design; but the other major cause is the lack of knowledge of OO principles. I am guilty of producing a few designs that I would rather not take a second look at, but there's hope for me yet, as I try to be a bit better each time I do it. Without further ado, let's get back to the square inhereting from rectangle.
For the mathematically inclined (or those who need a sleep aid), here's the formal definition of Liskov Substitution Principle (LSP for short):
What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.
In simpler terms, this means that it should be possible to use any subclass in place of its parent class. To observe the violation of this principle when using a square class that inherits from a rectangle, think about a method testing the calculation of the area of rectangle. Let's say it's defined like this:
public int testCalculateArea(Rectangle r)
{
r.Width = 10;
r.Height = 20;
return r.Width * r.Height;
}
If an object passed in to testCalculateArea() method is a rectangle (not a square), the result of the execution of the method above is clearcut: 200. However, if the object passed in to that method is a square, the result is not so obvious--should it be 100, 400, or 200? There's a violation of LSP here, and the real answer is that the square object cannot be polymorphic with the rectangle object without violating LSP.
Open Closed Principle
Let's say we modify the testCalculateArea() method above like this:
public int testCalculateArea(Rectangle r)
{
if r.isSquare()
{
return r.Width * r.Width;
}
else
{
r.Width = 10;
r.Height = 20;
return r.Width * r.Height;
}
}
Before the code could run, we would have to modify the original Rectangle class to include the method called isSquare(). Doing so would violate the Open Closed Principle (OPC), part of which states that classes should be sealed to avoid cascading changes to the existing clients of the code. Another part of the OPC states that classes should still be open for extension and adaptation. The easiest way to think about OPC is that public interfaces of the base classes should not be altered; but via sub-classing, addition of private fields/methods, and applying the Inversion of Control principle (discussed below), the classes can be extended.
Inversion of Control Principle
Also known as the "Hollywood Principle," the premise of the Inversion of Control (IoC) technique is simple: "Don't call us, we will call you." The IoC is a well-established technique: think about the callback functions that you may have registered with the remote, long-running web service to update the GUI upon the return of the data. This change of control flow, where the web service calls into the GUI (like Hollywood calling me) instead of the standard GUI calling into web service and waiting for data (me calling
Hollywood for years and still not being able to convince them of my unrivaled artistic ability) pretty much sums up the IoC principle. This tried-and-true OO principle could enhance user experiences with an application, reduce the load on the servers, and it is used extensively in various frameworks.
Dependency Inversion Principle
Dependency Inversion Principle is really a fancy name for the simple statement borrowed from the GoF's "Design Patterns": Program to the interfaces, not the implementations. A more formal definition (borrowed from DDJ) could go something like this:
-Higher level modules should not depend on lower level modules. Both should depend on abstractions (interfaces or abstract classes).
-Abstractions should not depend on implementations.
There is really not much else to say about the Dependency Inversion, it's a simple, yet fundamental principle of OO design.
Single Responsibility Principle
Another one of the fundamental principles, Single Responsibility Principle (SRP) is best summarized by Martin Fowler who said that "there should not be more than one reason for a class to change," or the class should have a single responsibility. If a class has more than one responsibility, it becomes more difficult to understand and reuse, because the responsibilities get coupled. And just as described in Steve McConnell's Code Complete, this cohesion (AKA single responsibility) principle should apply at the method level as well.
According to DDJ, the challenge with SRP is getting the granularity of responsibility right. For instance, should a business entity class persist itself into the database? There are several opinions and patterns on that, including Martin Fowler's "ActiveRecord" patter where each business class wraps a database row. But, there are several other authoritative statements that talk about separating the two concerns (business logic and persistence to the database).
The challenge with adhering to good OO principles is that the payback is not immediately apparent. There's a certain element of faith that requires a bit of extra diligence on the part of designer/architect for a promise of easier maitenance, better reuse and better stability of the system. But just like an artist trying to better him or herself with each stroke of the brush, applying these principles will, in time, give us the opportunity to paint a masterpiece that, in Geekland, will rival Dali's "The Persistence of Memory."