Embedded Real-Time Systems (TI-IRTS) General Design Principles 1 DIP The Dependency Inversion Principle Version: 22-2-2010
Dependency Inversion principle (DIP) DIP: A. High level modules should not depend upon low level modules. Both should depend upon abstractions. B. Abstractions should not depend upon details. Details should depend upon abstractions. Ref. The Dependency Inversion Principle, article by Robert C. Martin Slide 2
The Copy program (1) copy read Keyboard Structure chart write Printer void copy() // a C function { int c; while ( (c=readkeyboard())!= EOF) writeprinter(c); } Slide 3
The Enhanced Copy program (2) Changed requirement: The output should be either to a printer or to a disk enum OutputDevice {printer, disk}; void copy(outputdevice dev) { int c; while ( (c=readkeyboard())!= EOF) if (dev== printer) writeprinter(c); else writedisk(c); } The problem is that the high level policy i.e. the Copy module is dependent upon the low level detailed modules it controls. Slide 4
The OO Copy program (3) Copy Reader Notice: abstract classes Writer Keyboard Reader Printer Writer The dependency has been inverted! The copy class depends upon abstractions, and the detailed reader and writer depends upon the same abstractions Slide 5
The OO Copy program (4) class Reader { public: virtual int read() = 0; // pure virtual operation }; class Writer { public: virtual void write(char ch) = 0; // pure virtual operation }; void Copy(Reader& r, Writer& w) { int c; while ( (c=r.read())!= EOF) w.write(c); } Slide 6
Layering Simple Layers Policy Layer Mechanism Layer Utility Layer NB! The dependency is transitive Slide 7
Layering Abstract Layers Policy Layer Mechanism Interface Mechanism Layer Utility Interface NB! no transitive or direct dependency between layers Utility Layer Slide 8
An Inversion of Ownership Notice: inversion is also an inversion of ownership We often think of utility libraries as owning their own interfaces With DIP: The clients own the abstract interfaces The servers derives from them Known as the Hollywood principle: Don t call us, we ll call you Slide 9
Inverted Layers Policy Policy Layer «interface» Mechanism Interface Mechanism Mechanism Layer «interface» Utility Interface Utility Utility Layer Slide 10
A Simple Example (DIP) Dependency inversion can be applied where ever one object sends a message to another Button +Button(Lamp& l) +Detect() itslamp Lamp +TurnOn() +TurnOff() void Button::Detect() { bool buttonon= GetPhysicalState(); if (buttonon) itslamp->turnon(); else itslamp->turnoff(); } Slide 11
Example: Inverted Button Model Button +Detect(): void +GetState(): bool ButtonClient +TurnOn(): void +TurnOff(): void Reusable Button Implementation Button Imp.2 Lamp Motor +Detect(): void +GetState(): bool +TurnOn(): void +TurnOff(): void +TurnOn(): void +TurnOff(): void Slide 12
Template Method (GoF Pattern) The GoF Template method is a good example of DIP In this pattern a high level algorithm is encoded in an abstract base class and makes use of pure virtual functions to implements its details Derived classes implements those detailed virtual functions Thus, the class containing the details depends upon the class containing the abstraction Slide 13
Template Method - GoF Structure AbstractClass TemplateMethod() PrimitiveOperation1() PrimitiveOperation(2) // Common code PrimitiveOperation1() // more common code // PrimitiveOperation2() // ConcreteClass PrimitiveOperation1() PrimitiveOperation2() Notice: The Template Method is concrete Ref. GoF Design Patterns, Gamma et. al Slide 14
DIP - conclusion The principle of dependency inversion is at the root of many of the benefits claimed for object-oriented technology. Its proper application is necessary for the creation of reusable frameworks It is also critically important for the construction of code that is resilient to change Slide 15