里氏替换原则(Liskov Substitution principle)
网路上有很多文章与範例在解释6大原则,
但是还是很难只看一篇就能了解。
一言以蔽之 : 子类别必须可以替换父类别的功能
虽然是很简单的观念,但是理解起来还是很抽象。
今天就来统整一下这个原则吧
what is LSP?
以下截自wiki
里氏替换原则(Liskov Substitution principle)是对子类型的特别定义。
它由芭芭拉·里斯科夫(Barbara Liskov)在1987年在一次会议上名为「数据的抽象与层次」的演说中首先提出。
里氏替换原则的内容可以描述为: 「派生类(子类)对象可以在程式中代替其基类(超类)对象。」
在设计继承时,需符合子类别必须可以替换父类别的功能。
C# 之中有 IEnumerable > ICollection > IList > List
当interface实作时,需这样宣告
IList<int> myList = new List<int>(); //这就是里氏替换原则
为什么有这个原则呢?
我们在开发程式时,大部分的逻辑都是基于现实生活的,但是在撰写过程中常常因考虑不周全,导致执行结果正确,但却不符合现实情况,以下用常用的鸟类分类来解释:
所有的鸟类都继承"鸟"这个class
public class bird{ public void eat(...) public void fly(...) public void Location(...) ...}
所有鸟类都继承bird这个class这没有问题,但是有少数鸟类不会飞啊!!
如果让chicken直接继承,在程式方面虽然没错,但结果不是我们想要的,也不符合实际情况。
public class chicken:bird{ public void eat(...) public void fly(...) //chicken不会飞啊 public void Location(...) ...}
此种问题是因父类别的设计有问题造成的
我们可以藉由增加继承的层次来解决这个问题
在bird class 下多一层飞行的分类
public class flying:bird //会飞的{ public void fly(...) ...}public class flightless:bird //不会飞的{ ...}public class chicken:flyless //继承不会飞{ public void eat(...) public void Location(...) ...}
如此分开继承后,上层类别就可透过下层类别来实作,也不改变其行为
这样既不违背逻辑又可符合开闭原则
结论
里氏替换原则所规範的继承,子类别必须拥有父类别的全部属性和方法,避免子类别覆写父类别的功能(更改传回结果)
遵守里氏替换原则,可以建立良好的继承,降低继承造成的强耦合。