里氏替换原则

里氏替换原则,主要是一个关于继承的规范原则,它要求我们在软件中写继承关系时,所有引用父类的地方必须能够

明地使用其子类对象,子类可以实现父类所提供的抽象方法,但不要去重写父类已经实现的方法,或者重载父类的

造。要维护继承的传递性,当然很多地方为这个原则打了个比喻为:“龙生龙,凤生凤,老鼠的儿子会打洞”


里氏替换原则,告诉我们,在软件中将一个父类对象替换成它的子类对象,程序将不会产生任何错误或异常的话,那

这两个对象才具有继承关系,也就是IS-A关系。当然,反过来说,使用子类对象的地方却不一定都能使用其父类进

行替换,我相信这个应该很好理解,子类扩展的地方,父类就是没有办法实现的。


为了遵循里氏替换原则,我们在软件中通常有种写法,在程序中我们采用父类的基本类型来对对象进行定义,而在运

时再确定其子类类型,目的就是用子类对象来替换父类对象,所以很多原则,实际上在我们平时写代码这个过程

中,就有了体现。


在使用里氏替换原则时,需要注意的事项有:


1、子类的所有方法必须要在父类中有所声明,或者换句话说,就是子类必须实现父类中声明的所有方法。为什

么要有这个事项呢?其实很好理解,我们在写程序时,经常用父类来声明对象定义,这样有助于保证系统的扩展性,

在运行时用子类对象来替换父类对象,那么如果一个方法只存在子类中,在父类中却不提供对应的声明,那么父类对

对象如何去使用这个方法呢?


2、我们在使用里氏替换原则时,尽量把父类设计成抽象类或接口,让子类继承或实现其方法,运行时,由子类

对象替换掉父类对象,这样提高我们程序的扩展性,如果需要扩展其他类,无须修改原有子类的代码,只需要其他子

类继承或实现对应的父类或父接口即可,里氏替换原则其实也是开闭原则的一种体现。


举个符合替换原则的例子:

里氏替换原则_第1张图片


父类中,我们提供了2个方法,一个eat(),例外一个是breathe(),breathe()是一个抽象方法,因为这是子类特有的扩

展方法,父类无须实现, 但需要声明。eat()在父类中已经有过实现,那么子类只需继承即可,而无须重写,确保继承

的连贯性,老鼠的儿子不能连洞都不会打了,改去追狗了……。


代码体现:

package yuanze;

/**
 * 将父类声明为抽象类
 * 
 * @author Administrator
 *
 */
public abstract class Super {

	/**
	 * 定义一个父类无须实现的抽象方法
	 */
	public abstract void breathe();

	/**
	 * 定义父类需要实现的方法
	 */
	public void eat() {
		System.out.println("我吃面");
	}

}


子类:

package yuanze;

/**
 * 定义子类继承父类
 * 
 * @author Administrator
 *
 */
public class Child extends Super {
	/**
	 * 子类扩展的方法,但是在父类中有声明
	 */
	@Override
	public void breathe() {
		// TODO Auto-generated method stub
		System.out.println("呼吸");
	}

}



客户端调用时:

package yuanze;

public class Test {

	public static void main(String[] args) {

		Super c = new Child(); // 由子类的实例替代父类的实例
		c.eat();
	}
}


执行后的结果是:

我吃面



也就是说:子类继承父类后,无论继承多少次,那么只要eat(),那么就一定得到的是“我吃面”。如果子类重写了父类

的eat()方法,那么就可能出现“我跟着老婆走,我吃大米了!”的情况了,那就违背了里氏替换原则。可以这样理解,

父类中凡是已经实现好方法,那就是需要你继承着走的,那都是设计的一系列的规范和契约,如果任意去修改,就有

可能对整个继承体系造成破坏。子类需要扩展的方法,一定要通知到自己的父类,也就是需要在父类中声明。


通俗的说,这个原则就是:子类可以扩展父类的功能,但不能改变父类原有的功能。


1、子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法(不能把Y基因变成了Z,O(∩_∩)O哈哈~)。

2、子类中可以增加自己特有的方法,但需要在父类中声明(要跟到老婆走,是不先要给父亲说些呢?)。

3、当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松,这个

从参数个数上考虑。

4、当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更加严格,如父类要

求返回List,那么子类就应该返回List的实现ArrayList,父类是采用泛型,那么子类则不能采用泛型,而是具体的返

回。

你可能感兴趣的:(里氏替换原则)