里氏替换原则

里氏替换原则的由来

里氏替换原则(Liskov Substitution Principle LSP)是由麻省理工学院计算机科学实验室的Liskov(里斯科瓦)女生提出的。
在1987年的OOPSLA大会上发表的一篇文《DataAbstractionand Hierarchy》里面提出来的,主要阐述了有关继承的一些规则, 就是什么时候使用继承,什么时候不应该使用继承,以及其中蕴含的原理。

 

里氏替换原则的定义   

第一种定义: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.

如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。

第二种定义:Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.

所有引用基类的地方必须能透明地使用其子类的对象

 

里氏替换原则的含义

1.子类必须完全实现父类的方法

2.子类可以增加自己特有的方法

3.覆盖或实现父类的方法时输入参数可以被放大

4.覆盖或实现父类的方法时输出结果可以被缩小

 

里氏替换原则的例子

   A类实现两个数相减的功能 

 1 public class A
 2     {
 3         public int fun1(int a, int b)
 4         {
 5             return a - b;
 6         }
 7     }
 8 class Program
 9     {
10         static void Main(string[] args)
11         {
12             A a = new A();
13             Console.WriteLine("100-50="+a.fun1(100,50));
14             Console.WriteLine("100-80="+a.fun1(100, 80));
15             Console.Read();
16         }
17     }

 

显示结果
后来,我们需要增加一个新的功能:完成两数相加,然后再与100求和,由类B来负责 

 1 class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             B b = new B();
 6             Console.WriteLine("100-50="+b.fun1(100,50));
 7             Console.WriteLine("100-80="+b.fun1(100, 80));
 8             Console.WriteLine("100+20+100="+b.fun2(100, 20));
 9             Console.Read();
10         }
11     }
12 
13     public class B : A
14     {
15         public int fun1(int a, int b)
16         {
17             return a + b;
18         }
19 
20         public int fun2(int a,int b)
21         {
22             return fun1(a, b) + 100;
23         }
24    }

显示结果  

我们发现原本运行正常的相减功能发生了错误。
原因就是类B在给方法起名时无意中重写了父类的方法,造成所有运行相减功能的代码全部调用了类B重写后的方法,造成原本运行正常的功能出现了错误。
类B继承类A时,除添加新的方法完成新增功能P2外,尽量不要重写父类A的方法,也尽量不要重载父类A的方法。
如果非要重写父类的方法,比较通用的做法是:原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉,采用依赖、聚合,组合等关系代替。

 

我的理解

里氏替换原则是为了保证继承的正确性而存在的。
根本要求就是父类出现的地方子类能够替换,如果不能替换就是不合理的继承。
比如鸵鸟不是鸟的问题,一般来说鸟都会飞的,鸵鸟可以继承鸟,但他不会飞。当父类鸟出现时要用到飞的方法时,鸵鸟是不能替换它的,因为他不会飞,所以他不是鸟。
这时我们可以针对接口和抽象来编程,把飞的方法放到一个接口中。父类中凡是已经实现好的方法(相对于抽象方法而言),
实际上是在设定一系列的规范和契约,虽然它不强制要求所有的子类必须遵从这些契约,
但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。

 

 

 

 

 

  

posted @ 2013-03-06 14:15  小跳蚤  阅读(521)  评论(0编辑  收藏  举报