Flylib.com

Books Software

 
 
 

Heuristics and Conventions


Heuristics and Conventions

Some simple heuristics can give you some clues about LSP violations. These heuristics all have to do with derivative classes that somehow remove functionality from their base classes. A derivative that does less than its base is usually not substitutable for that base and therefore violates LSP.

Consider Figure 10-13. The f function in Base is implemented but in Derived is degenerate . Presumably, the author of Derived found that function f had no useful purpose in a Derived . Unfortunately, the users of Base don't know that they shouldn't call f , and so there is a substitution violation.

Listing 10-13. A degenerate function in a derivative
public class Base
{
  public virtual void f() {/*some code*/}
}

public class Derived : Base
{
  public override void f() {}
}

The presence of degenerate functions in derivatives is not always indicative of an LSP violation, but it's worth looking at them when they occur.



Conclusion

The Open/Closed Principle is at the heart of many of the claims made for object-oriented design. When this principle is in effect, applications are more maintainable , reusable, and robust. The Liskov Substitution Principle is one of the prime enablers of OCP. The substitutability of subtypes allows a module, expressed in terms of a base type, to be extensible without modification. That substitutability must be something that developers can depend on implicitly. Thus, the contract of the base type has to be well and prominently understood , if not explicitly enforced, by the code.

The term IS-A is too broad to act as a definition of a subtype. The true definition of a subtype is substitutable , where substitutability is defined by either an explicit or implicit contract.



Bibliography

[Liskov88] "Data Abstraction and Hierarchy," Barbara Liskov, SIGPLAN Notices , 23(5) (May 1988).

[Meyer97] Bertrand Meyer, Object-Oriented Software Construction , 2d. ed., Prentice Hall, 1997.

[Wirfs-Brock90] Rebecca Wirfs-Brock et al. , Designing Object-Oriented Software , Prentice Hall, 1990.



Chapter 11. The Dependency-Inversion Principle (DIP)

Jennifer M. Kohnke

Nevermore Let the great interests of the State depend Upon the thousand chances that may sway A piece of human frailty

Sir Thomas Noon Talfourd (17951854)

The Dependency-Inversion Principle

  1. High-level modules should not depend on low-level modules. Both should depend on abstractions.

  2. Abstractions should not depend upon details. Details should depend upon abstractions.


Over the years , many have questioned why I use the word inversion in the name of this principle. The reason is that more traditional software development methods, such as structured analysis and design, tend to create software structures in which high-level modules depend on low-level modules and in which policy depends on detail. Indeed, one of the goals of these methods is to define the subprogram hierarchy that describes how the high-level modules make calls to the low-level modules. The initial design of the Copy program in Figure 7-1 is a good example of such a hierarchy. The dependency structure of a well-designed object-oriented program is "inverted" with respect to the dependency structure that normally results from traditional procedural methods.

Consider the implications of high-level modules that depend on low-level modules. It is the high-level modules that contain the important policy decisions and business models of an application. These modules contain the identity of the application. Yet when these modules depend on the lower-level modules, changes to the lower-level modules can have direct effects on the higher-level modules and can force them to change in turn .

This predicament is absurd! It is the high-level, policy-setting modules that ought to be influencing the low-level detailed modules. The modules that contain the high-level business rules should take precedence over, and be independent of, the modules that contain the implementation details. High-level modules simply should not depend on low-level modules in any way.

Moreover, it is high-level, policy-setting modules that we want to be able to reuse. We are already quite good at reusing low-level modules in the form of subroutine libraries. When high-level modules depend on low-level modules, it becomes very difficult to reuse those high-level modules in different contexts. However, when the high-level modules are independent of the low-level modules, the high-level modules can be reused quite simply. This principle is at the very heart of framework design.