CS3342 Lecture 6

Software Design Principles - OCP, LSP, DIP

Software design principles: Characteristics of Good Software Design. 

  • Single Responsibility Principle (SRP)
  • Open-Closed Principle (OCP)
  • Liskov Substitution Principle (LSP)
  • Interface Segregation Principle (ISP)
  • Dependency Inversion Principle (DIP)
  • Law of Demeter Principle (LoD)

 


Open-Closed Principle (OCP)

Software entities (class, modules, functions, etc)

  • should be Open for Extension
  • but Closed for Modification

OCP provides a better design structure

Be open for extension: Class functional behavior can be further extended (easily)
Be closed for modification: When extending the behavior of a class module, the core functions should not be changed. Important attributes should not be directly accessible/modifiable.

Target of our programming style: Modules should be written so they can be extended without requiring them to be modified

Example:

Solution: Get rid of IF… THEN… ELSE 

Even if we put function Copy in a class, the behavior of this function Copy cannot be extended easily, because of the if-then-else structure in Copy is highly depending on the output device type.

Now, irrespective the concrete subclass of device used, function Copy can always call a single Write(int c) function, for ANY device, including newly added. 
Solution:

     

Best Solution: OCP Abstraction 

 => 

This is a better designed solution: A class must not (directly) depends on a concrete class! Specifically, the code in the client class (Car) does not directly call a method of another concrete method (class).

Example:

OCP Heuristics – Private Data (-)

Make all object-data, variables within an object private. (No public Variables (publically accessible data)!)

Maintaining public variable/data is always risky, because it may “open” the module for other objects to perform some harmful tasks.
They may produce a rippling effect requiring maintenance at many unexpected locations, due to code dependencies.
Errors are difficult to be located and fixed. Fixes may cause undesirable errors elsewhere because of such data dependencies.
Good Design Example:
BankUser cannot access private balance of Account!
BankUser can only access data via public method calls of Account. 

Summary:

  Design Principle
  • Open for extension – easily to add new functions
  • Closed for modification and access – minimize impacts to existing code when making a change or an addition.
  Implementation
  • Use class abstraction (interface/abstract in Java or virtual class in C++) for what is common in the variation
    • Java “Interface” : implicit abstract and cannot have implementations
       
    • Java “Abstract” : can implement default behaviors.
  • Use subclassing (or polymorphism) to provide different behaviors in subclasses. 

 


Liskov Substitution Principle (LSP)

By Barbara Liskov (MIT Professor) 

LSP Keywords:

  • Substitutability / Replaceable?
  • The Definition/Measure of a subtyping relation
  • Strong behavioural subtyping
An extension of OCP
  • Ensure that new derived subclasses ONLY extending the base-class
  • Without changing their behaviour
The key of open-close principle (OCP): Abstraction and Polymorphism. Implemented by inheritance with abstract/interface

Derived subclasses (sub-types) must be completely substitutable for their parent class (base type).

A subtype as if it were its base type in reasoning for its intention, interaction and effects on the other classes.
  • i.e. Substituted / Replaced by another set of implementations.
  • Can an iPad be abstracted and reasoned as a computer? If Yes, then class iPad can inherit from class Computer.

  

LSP is about Meaning and Substitution

  • Make sure subclasses can be used to “replace” their parent class.
  • Subclass could have additional features. 
  • Subclass should not inherit features don’t exist in the actual context! 

LSP problem

  Analysis:

  • For a Square, the attributes Height and Width must be equal.
  • We can override setHeight and setWidth to perform the same task (i.e., we duplicate the code in two functions),
  • BUT we cannot control any caller object of a Square object to use the sequence of these methods semantically meaningful

 


Dependency Inversion Principle (DIP)

  • A specific form of decoupling software modules.
  • Direction of dependency matters

I.  High-level modules should not depend on Low-level modules.

    Both should depend on abstractions.

II. Abstractions should not depend on details.

    Details should depend on abstractions.

A super class in an inheritance hierarchy should not know any information about its subclasses.
Classes with detailed implementations must depend upon their abstractions, but not vice versa.
OCP states the goal; DIP using abstract/virtual class or interface  is a way to achieve OCP.

DIP Violation

 

  • All classes in the diagram on the above are concrete classes.
  • ABussinessClass in the business (top) layer depends on AServiceClass in the service (middle) layer. Similarly, AServiceClass depends on a AUtilityClass in the utility (bottom) layer, e.g., the code of ABussinessClass calls a method of AServiceClass.
  • Thus, the above business class depends transitively on the classes at the bottom layer.
  • This is poor in design because changes in low level modules may lead to changes in high-level modules.
  • Also, high-level modules will be more difficult to reuse in other contexts

We can invert the dependencies by using interfaces declared in the upper layer.
Now, the Business layer no longer depends on any concrete class in the Service layer.
The entire Business layer can be reused.
Thus, Dependency Inversion.
 
DIP Related Heuristics/Guideline

Design towards an Interface, NOT an implementation.

Use abstract class/interface to avoid direct bindings to concrete classes:

When in Doubt(if not sure…), add a new Level of indirectness

If the abstraction of a concrete class seems, still unsatisfactory (not General Enough), then creates a more general abstraction.

DIP Example:

Violation of the DIP principle (if followed)
  • Button directly depends on Lamp.
  • Button cannot be reused for other appliances (e.g., SpotLight). becauce: Private Lamp lamp; explicitly declared
Strategy to improve the current design
  • Create a generalized interface Appliance, for the operations of “turningOn()” and “turningOff()”.
  • Revise the Button class so that Button class depends on the newly created generalized interface Appliance.
  • Different appliances can now be implemented using this generalized interface, and be controlled by pushButton().

 

Summary:

  • Both low-level class and high-level class depend on their abstractions (i.e. abstract or interface classes)
  • High-level modules owns the interface (e.g., create a demand of the operations in the interface and hence determine the content of the interface)
  • Common interface is an important for Software Engineering Dev. Teams, for software enhancement, maintenance, upgrades..etc. 
  • Low-level classes should implement toward their interface.
 

Summary of OCP,LSP,DIP

Open Close Principle (OCP)
  • Open for Extension
  • Closed for modification
Liskov’s Substitution Principle (LSP)
  • The design of a subclass can be a substitute of its parent class
  • Subclass must comply with their superclass
Dependency Inversion Principle (DIP)
  • Avoid incorrect dependency
  • Use interface/abstract for better extension

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2018-03-25 11:14  Charonnnnn  阅读(301)  评论(0编辑  收藏  举报