Agile Software Development: principles, patterns and practices--the 10th chapter Lsp:liskov substitution principle

Source: Internet
Author: User

10th Chapter Lsp:liskov Substitution principle

Liskov substitution principle: subtypes (subtype) must be able to replace their base types (base type).


10.1 Violations of LSP

10.1.1 Simple Example

Violations of the LSP resulted in a violation of the OCP:

structPoint {Doublex, y;} Public enumshapetype {square, circle}; Public classshape{PrivateShapeType type;  PublicShape (ShapeType t) {type =T;}  Public Static voidDrawshape (Shape s) {if(S.type = =shapetype.square) (s asSquare).        Draw (); Else if(S.type = =shapetype.circle) (s asCircle).    Draw (); }} Public classcircle:shape{PrivatePoint Center; Private Doubleradius;  PublicCircle ():Base(shapetype.circle) {} Public voidDraw () {/*Draws the Circle*/}} Public classsquare:shape{PrivatePoint topleft; Private Doubleside;  PublicSquare ():Base(shapetype.square) {} Public voidDraw () {/*draws the square*/}}

It is clear that the Drawshape function violates the OCP. It must know every possible derived class of the shape class and must change it each time a new class derived from the shape class is created.


10.1.2 more subtle violations of the situation

Here is a rectangle type:

PublicClassrectangle{PrivatePoint TopLeft;private double width; Span style= "color: #0000ff;" >private double height; public double Width { Span style= "color: #0000ff;" >get {return width;} set {width = value;}} public double Height { Span style= "color: #0000ff;" >get {return height;} set {height = value;}}        

One day, users ask for the ability to add squares.

We often say that inheritance is a is-a (is a) relationship. In a general sense, a square is a rectangle. It is therefore logical to treat the square class as derived from the rectangle class. However, this idea brings some subtle but several issues that merit attention. In general, these problems are difficult to meet until we write the code to find out.

The square class does not require both height and width. But Square will still inherit them from the rectangle. Obviously it's a waste. Let's say we don't really care about memory efficiency. Write the following self-compatible rectangle class and square class code:

 Public classrectangle{PrivatePoint topleft; Private Doublewidth; Private Doubleheight;  Public Virtual DoubleWidth {Get{returnwidth;} Set{width =value;} }     Public Virtual DoubleHeight {Get{returnheight;} Set{height =value;} }} Public classsquare:rectangle{ Public Override DoubleWidth {Set        {            Base. Width =value; Base. Height =value; }    }     Public Override DoubleHeight {Set        {            Base. Height =value; Base. Width =value; }    }}

The real problem

Now square and rectangle all seem to work. It seems that the design is self-compatible and correct. However, this conclusion is wrong. A self-compatible design is not necessarily compatible with all user programs. Consider the following function:

    void g (Rectangle R)    {        5;         4 ;         if  - )            thrownew Exception ("badarea! " );    }

For rectangle, this function works correctly, but throws an exception if the square object is passed in. All, the real question is: The writer of function G assumes that changing rectangle often does not result in wide changes.

Obviously, changing the width of a rectangle does not affect his long yes hypothesis is reasonable! However, not all objects passed as rectangle satisfy this hypothesis. The function g is fragile for square and rectangle hierarchies. For G, Square cannot replace rectangle, so the relationship between square and rectangle is a violation of the LSP.

Validity is not an essential attribute

A model, if seen in isolation, does not have a true sense of validity. The validity of the model can only be represented by its client program. So, as with other principles, just predict the most obvious breaches of the LSP and postpone all other predictions until the associated vulnerability stinks.

ISA is about behavior.

The is-a relationship in Ood is in the way of behavior, and the behavior mode can be reasonably assumed, which is the client program depends on.


10.2 Replacing inheritance with methods of extracting public parts

See the following code:

 Public classline{PrivatePoint p1; PrivatePoint p2;  PublicLine (Point P1, point p2) { This. P1 = P1; This. P2 =P2;}  PublicPoint P1 {Get{returnP1;} }     PublicPoint P2 {Get{returnP2;} }     Public DoubleSlope {Get{/*Code*/} }     Public Doubleyintercept {Get{/*Code*/} }     Public Virtual BOOLIsOn (point P) {/*Code*/}} Public classlinesegment:line{ PublicLineSegment (Point P1, point P2):Base(P1, p2) {} Public DoubleLength () {Get{/*Code*/} }     Public Override BOOLIsOn (point P) {/*Code*/}}

At first glance, they will feel that there is a natural inheritance between them. However, these two classes still violate the LSP in subtle ways.

Line users can expect all points that have a linear linear correspondence with the. For example, the point returned by the Yintercept property is the intersection of the line and the axis. Since this point has a linear correspondence with the line, the user of the lines can expect ISON (yintercept ()) ==true. However, for many instances of LineSegment, this statement will fail.

A simple solution solves the problem of line and LineSegment, which also illustrates an important tool for Ood. If we can have access to both the line class and the LineSegment class, we can propose an abstract base class for the public part of these two classes. As follows:

 Public Abstract classlinearobject{PrivatePoint p1; PrivatePoint p2;  PublicLinearobject (Point p1, point p2) { This. P1 = P1; This. P2 =P2;}  PublicPoint P1 {Get{returnP1;} }     PublicPoint P2 {Get{returnP2;} }     Public DoubleSlope {Get{/*Code*/} }     Public Doubleyintercept {Get{/*Code*/} }     Public Virtual BOOLIsOn (point P) {/*Code*/}} Public classline:linearobject{ PublicLine (Point P1, point P2):Base(P1, p2) {} Public Override BOOLIsOn (point P) {/*Code*/}} Public classlinesegment:linearobject{ PublicLineSegment (Point P1, point P2):Base(P1, p2) {} Public DoubleGetLength () {/*Code*/}     Public Override BOOLIsOn (point P) {/*Code*/}}

Extracting the public part is an effective tool. If there are some common features in the two classes, then it is likely that other classes will later appear to have those attributes. For example, the Ray class:

 Public class ray:linearobject{    publicbase(P1, p2) {/*code*/}      Public Override BOOL IsOn (point P) {/*code*/}}


10.3 Heuristic rules and idioms

Derived classes that perform less than the base class typically cannot replace their classes, and therefore violate the LSP.

See the following code:

 Public class base{    publicvirtualvoid f () {/*some code* / }}publicclass  derived:base{    publicoverride  void  f () {}}

The function f is implemented in base. However, in derived, the function f is degenerate. Perhaps, derived programmers think that function f is useless in derived. Unfortunately, base users do not know that they should not call F, so there is a substitution violation.

The existence of degenerate functions in degenerate classes does not always mean that the LSP is violated, but it is worth noting when this is the case.


10.4 Conclusion
The OCP is at the heart of many of Ood's claims. LSP is one of the main reasons for making OCP possible.
The meaning of the term is-a is too broad to be defined as a subtype. The correct definition of a subtype is replaceable.

Excerpt from: "Agile Software Development: principles, patterns and Practices (C # Edition)" Robert C.martin Micah Martin

Reprint please specify the source:

Jesselzj
Source: http://jesselzj.cnblogs.com

Agile Software Development: principles, patterns and practices--the 10th chapter Lsp:liskov substitution principle

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.