What is an example of the Liskov Substitution Prin

2018-12-31 00:48发布

I have heard that the Liskov Substitution Principle (LSP) is a fundamental principle of object oriented design. What is it and what are some examples of its use?

26条回答
浪荡孟婆
2楼-- · 2018-12-31 01:46

The clearest explanation for LSP I found so far has been "The Liskov Substitution Principle says that the object of a derived class should be able to replace an object of the base class without bringing any errors in the system or modifying the behavior of the base class" from here. The article gives code example for violating LSP and fixing it.

查看更多
梦醉为红颜
3楼-- · 2018-12-31 01:49

The LSP is a rule about the contract of the clases: if a base class satisfies a contract, then by the LSP derived classes must also satisfy that contract.

In Pseudo-python

class Base:
   def Foo(self, arg): 
       # *... do stuff*

class Derived(Base):
   def Foo(self, arg):
       # *... do stuff*

satisfies LSP if every time you call Foo on a Derived object, it gives exactly the same results as calling Foo on a Base object, as long as arg is the same.

查看更多
孤独寂梦人
4楼-- · 2018-12-31 01:50

Substitutability is a principle in object-oriented programming stating that, in a computer program, if S is a subtype of T, then objects of type T may be replaced with objects of type S

let's do a simple example in Java:

Bad example

public class Bird{
    public void fly(){}
}
public class Duck extends Bird{}

The duck can fly because of it is a bird, But what about this:

public class Ostrich extends Bird{}

Ostrich is a bird, But it can't fly, Ostrich class is a subtype of class Bird, But it can't use the fly method, that means that we are breaking LSP principle.

Good example

public class Bird{
}
public class FlyingBirds extends Bird{
    public void fly(){}
}
public class Duck extends FlyingBirds{}
public class Ostrich extends Bird{} 
查看更多
冷夜・残月
5楼-- · 2018-12-31 01:50

This formulation of the LSP is way too strong:

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.

Which basically means that S is another, completely encapsulated implementation of the exact same thing as T. And I could be bold and decide that performance is part of the behavior of P...

So, basically, any use of late-binding violates the LSP. It's the whole point of OO to to obtain a different behavior when we substitute an object of one kind for one of another kind!

The formulation cited by wikipedia is better since the property depends on the context and does not necessarily include the whole behavior of the program.

查看更多
人间绝色
6楼-- · 2018-12-31 01:50

Would implementing ThreeDBoard in terms of an array of Board be that useful?

Perhaps you may want to treat slices of ThreeDBoard in various planes as a Board. In that case you may want to abstract out an interface (or abstract class) for Board to allow for multiple implementations.

In terms of external interface, you might want to factor out a Board interface for both TwoDBoard and ThreeDBoard (although none of the above methods fit).

查看更多
只若初见
7楼-- · 2018-12-31 01:51

Let's say we use a rectangle in our code

r = new Rectangle();
// ...
r.setDimensions(1,2);
r.fill(colors.red());
canvas.draw(r);

In our geometry class we learned that a square is a special type of rectangle because its width is the same length as its height. Let's make a Square class as well based on this info:

class Square extends Rectangle {
    setDimensions(width, height){
        assert(width == height);
        super.setDimensions(width, height);
    }
} 

If we replace the Rectangle with Square in our first code, then it will break:

r = new Square();
// ...
r.setDimensions(1,2); // assertion width == height failed
r.fill(colors.red());
canvas.draw(r);

This is because the Square has a new precondition we did not have in the Rectangle class: width == height. According to LSP the Rectangle instances should be substitutable with Rectangle subclass instances. This is because these instances pass the type check for Rectangle instances and so they will cause unexpected errors in your code.

This was an example for the "preconditions cannot be strengthened in a subtype" part in the wiki article. So to sum up, violating LSP will probably cause errors in your code at some point.

查看更多
登录 后发表回答