"围观"设计模式(2)--里氏替换原则(LSP,Liskov Substitution Principle)

原创 2016年04月15日 21:06:54

面向对象的程序设计中,里氏替换原则(Liskov Substitution principle)是对子类型的特别定义。它由芭芭拉·利斯科夫(Barbara Liskov)在1987年在一次会议上名为“数据的抽象与层次”的演说中首先提出。

里氏替换原则的内容可以描述为: “派生类(子类)对象能够替换其基类(超类)对象被使用。” 以上内容并非利斯科夫的原文,而是译自罗伯特·马丁(Robert Martin)对原文的解读。其原文为:

Let q(x) be a property provable about objectsx of typeT. Thenq(y) should be true for objectsy of typeS whereS is a subtype ofT.

芭芭拉·利斯科夫与周以真(Jeannette Wing)在1994年发表论文并提出的以上的Liskov代换原则。----维基百科


里氏替换原则我个人的理解是:在继承关系中,父类的对象如果替换为子类的对象,他原来执行的行为依然保持不变,那么这样的程序才符合里氏替换原则,否则违背了里氏替换原则。


下面我们看这样一个实例,体会下,里氏替换原则是在什么情况下违背的。


一个简单的继承结构,在子类中,重写父类的方法calc方法。

父类Calc:

package cn.design.pattern2016032004LiskovSubstitutionPrinciple;

public class Calc {

	public void calc(int a, int b) {
		// a-b = ?
		System.out.println(a + " - " + b + " = " + (a - b));
		
	}
}

子类CalcSon,通过将父类中calc这个方法重写为两个数相加。

package cn.design.pattern2016032004LiskovSubstitutionPrinciple;

public class CalcSon extends Calc{

	public void calc(int a, int b) {
		// a+b = ?
		System.out.println(a + " + " + b + " = " + (a + b));
	}
	
	// other method
	public void addThem(int a, int b) {
		System.out.println(a + b);
	}
}

测试类:这里如果符合里氏替换原则的话,那么应该说将父类的调用的这个地方直接换为子类的话,那么原来的行为不会发生任何的改变。但是下面的程序证明了,这样的做法是违背了里氏替换原则的。将原先父类调用的替换为子类的时候,会由原来的父类的方法:减法,变为现在子类中的:加法。结果发生变化,从而违背了里氏替换原则。

Calc cal = new Calc();
cal.calc(10, 20);
		
/**
* 根据里氏替换原则,当父类替换为子类的时候,使用父类的时候的行为不应该
* 发生变化,那么下面的这段代码,显然发生了变化,这样显然违反了里氏替换
* 原则。
*/
Calc calcSon = new CalcSon();
calcSon.calc(10, 20);

我们在子类继承父类之后,重写了父类的方法时,需要注意,这样的做法并不好,降低了整个继承体系的复用性,出错几率会相应的增加。


总结前人的诸多经验来看,里氏替换原则主要是有四点:

1. 子类不要覆盖父类的非抽象的方法。可以实现其抽象方法。

2. 子类可以实现自己独有的方法。

3. 子类的方法重写父类方法的时候,参数部分,要比父类的参数范围要大或者等于(宽松)。释义:举个例子>如果说父类的方法中形参是ArrayList,那么,其子类重写这个方法的时候,形参要是List.

4. 子类重写父类方法的时候,返回值要求,父类的返回值要比子类的返回值要小于或者等于。



面对这样的情况,一般的,将当前的继承结构解除掉,变为依赖或者聚合组合的形式。抽象出更高一层的抽象类,定义好这样的一个抽象方法,同时由原先的两个类继承实现。


public abstract class Calculator {

	public abstract void calc(int a, int b);
}

public class Calc extends Calculator{

	public void calc(int a, int b) {
		// a-b = ?
		System.out.println(a + " - " + b + " = " + (a - b));
		
	}
}

public class CalcSon extends Calculator{

	public void calc(int a, int b) {
		// a+b = ?
		System.out.println(a + " + " + b + " = " + (a + b));
	}
	
	// other method
	public void addThem(int a, int b) {
		System.out.println(a + b);
	}
}

通过这样的途径将原来的继承结构重新解构重组后的继承体系,应该说相对来说,出错的几率大大降低了。

源码已经上传至GitHub:下载设计模式代码




版权声明:本文为博主原创文章,未经博主允许不得转载。

LSP简介(LSP--Liskov Substitution Principle)

 一、LSP简介(LSP--Liskov Substitution Principle):定义:如果对于类型S的每一个对象o1,都有一个类型T的对象o2,使对于任意用类型T定义的程序P,将o2替换为o...
  • mydriverc
  • mydriverc
  • 2007年06月20日 13:14
  • 801

替换原则(LSP - Liskov Substitution Principle)

如何设计最佳的继承层次?  怎样避免类层次结构不符合OCP ? 答案就是替换原则(LSP): 子类型必须能够替换调它们的基类型。 代码违反LSP原则的明显特征: 使用if 或 if/else 去确...
  • qq_18497495
  • qq_18497495
  • 2016年11月01日 09:24
  • 207

设计模式六大原则(2):里氏替换原则

肯定有不少人跟我刚看到这项原则的时候一样,对这个原则的名字充满疑惑。其实原因就是这项原则最早是在1988年,由麻省理工学院的一位姓里的女士(Barbara Liskov)提出来的。 定义1:如果对每...
  • zhengzhb
  • zhengzhb
  • 2012年02月22日 08:46
  • 91697

面向对象设计原则之里氏代换原则

里氏代换原则由2008年图灵奖得主、美国第一位计算机科学女博士Barbara Liskov教授和卡内基·梅隆大学Jeannette Wing教授于1994年提出。其严格表述如下:如果对每一个类型为S...
  • LoveLion
  • LoveLion
  • 2012年05月06日 21:56
  • 30803

六大设计原则之里氏替换原则

里氏替换原则定义里氏替换原则(Liskov Substitution Principle,LSP): 第一种定义:如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所...
  • hfreeman2008
  • hfreeman2008
  • 2016年08月28日 11:27
  • 1854

设计模式六大原则: 狸猫换太子 -- 里氏替换原则

据野史传说中记载,当年宋哲宗最宠爱的妃子是刘德妃。刘德妃虽然深受皇上宠爱,但是却久久不能生育。刘德妃为竞争皇后之位,提高自己的身价,便想出了“借腹怀孕”的诡计。她打算利用身旁的一个长得有些姿色的姓李的...
  • u011240877
  • u011240877
  • 2016年08月11日 23:57
  • 3667

设计原则(二)里氏替换原则(LSP)

一、什么是里氏替换原则 里氏替换原则的严格表达是:如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都替换成o2时,程序P的行为没有变化,那么类型...
  • xingjiarong
  • xingjiarong
  • 2015年11月29日 11:03
  • 2642

开闭原则与里氏替换原则

1.开闭原则 是面向对象设计的基本原则之一,是“可复用设计”的基础,它的主要原则是:对扩展开放,对修改关闭;意思就是我们改变一个软件时。应该通过扩展方式来改变软件,而不是修改原有的代码。 2.里氏...
  • wei78008023
  • wei78008023
  • 2015年03月19日 14:59
  • 724

里氏替换原则

里氏替换原则,主要是一个关于继承的规范原则,它要求我们在软件中写继承关系时,所有引用父类的地方必须能够 透明地使用其子类对象,子类可以实现父类所提供的抽象方法,但不要去重写父类已经实现的方法,或者重载...
  • pu_xubo565599455
  • pu_xubo565599455
  • 2016年05月24日 14:00
  • 907

设计模式六大原则:里氏替换原则(五)

转载请标明:http://blog.csdn.net/liulongling/article/details/51383159 面向对象其它六大原则 单一职责原则-带你走梦幻西游(一) 依赖...
  • liulongling
  • liulongling
  • 2016年05月12日 12:42
  • 2320
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:"围观"设计模式(2)--里氏替换原则(LSP,Liskov Substitution Principle)
举报原因:
原因补充:

(最多只允许输入30个字)