设计模式——(五)设计模式原则___里氏替换原则

一、介绍

里氏替换原则是指:
如果对每个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1代换为o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。
换句话说,所有引用基类的地方必须能透明地引用其子类的对象。
在使用继承时,遵循里氏替换原则,在子类中尽量不要重写父类的方法。
里氏替换原则告诉我们,继承实际上让两个类的耦合性增强了,在适当的情况下,可以通过聚合、组合、依赖来解决问题。

关于面向对象程序设计中的继承性的思考和说明:
1)继承包含这样的一层含义:父类中凡是已经设定好的方法,实际上是在设定规范和契约,虽然它没强制性要求所有的子类必须遵守这些契约,但是如果子类对这些已经实现的方法进行任意的修改,那么就会对整个进程体系造成破坏。
2)继承在给整个程序设计带来便利的同时,也对程序带来了弊端,如使用继承会给程序带来侵入性,程序的可移植性降低,增加对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须要考虑到所有的子类,且当父类被修改时,所有的子类都可能出现故障。
所以,我们在继承的时候需要遵守里氏替换原则。

二、应用

我们来看以下的一个例子:

class A{
	public int func1(int num1,int num2){
		return  num1-num2;
	}
}

class B extends A{
	public int func1(int a,int b) {
		return a + b;
	}
	public int func2(int a,int b) {
		return func1(a,b) + 9;
	}
}

代码十分简单,A需要实现两个数相减的功能,而B似乎想要增加两个新的计算功能。
但是这里出现了问题:不知道B怎么就把增加的其中一个功能取名叫func1(大概是不小心),这样就把A类中的func1给重写了。
也就是说,我们在使用的时候,就无法正常使用A中的func1这个功能了。我们可以看到,在编程中我们经常采用的这种重写父类的方法来完成新的功能,虽然写起来比较简单,但是可复用性较差。

通常的解决方案是:
原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉,采用委托的方式来代替。

如下,我们采用委托的方式


class Base{
	
}

class A extends Base{
	public int func1(int num1,int num2){
		return  num1-num2;
	}
}

class B extends Base{
	
	private A a = new A();

	public int func1(int a,int b) {
		return a + b;
	}
	public int func2(int a,int b) {
		return func1(a,b) + 9;
	}
	//提供了使用A的func1的功能
	public int func3(int num1,int num2) {
		return this.a.func1(num1, num2);
	}
}

这样一来,我们在编程中,所有的A类对象替换成B类对象的时候,程序不会发生故障。

三、补充

在软件构造课程中对里氏替换原则有着更为细致的解释:
在静态类型检查中是这么体现的:
1)子类型可以增加方法,但不可删去原有的方法
2)子类型需要实现抽象类型中的所有未实现方法
3)子类型中重写的方法必须有相同或子类型的返回值或者符合“协变”的参数
4)子类型中重写的方法必须使用同样类型的参数或者符合逆变的参数
在特定行为的角度是这么体现的(就方法而言):
1)更强的不变量
2)更弱的前置条件
3)更强的后置条件

这里解释一下协变和异变:
这些词眼看起来非常玄乎,其实也没那么复杂:协变顾名思义
就是“跟着变”,异变就是“反着变”。
也就是说,以父类到子类的规约变化为基准,某个东西跟着变(变强)就是协变,反着变(变弱)就是异变。

这也很好理解:从父类到子类,规约自然是要越来越强的,而我们说返回值要符合“协变”,这是当然:客户期望得到一个更为清晰、准确、具体的返回值;而参数要符合“异变”,也就是说客户希望自己的输入能够尽可能自由、尽可能适应更多的情况。当然,满足里氏替换原则的意义是:我可以选择并不更宽泛的前置条件,期望返回一个跟原来一样不那么具体的返回值,这种做法的正确性是毫无疑问的:也就是我们可以做到把父类对象替换成子类之后,原来的程序完全能够正常地运行并实现原有的功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值