设计模式六大原则(2):里氏替换原则(Liskov Substitution Principle)
肯定有不少人跟我刚看到这项原则的时候一样,对这个原则的名字充满疑惑。事实上原因就是这项原则最早是在1988年,由麻省理工学院的一位姓里的女士(Barbara Liskov)提出来的。
定义1:假设对每个类型为 T1的对象 o1,都有类型为 T2 的对象o2。使得以 T1定义的全部程序 P 在全部的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。
定义2:全部引用基类的地方必须能透明地使用其子类的对象。
问题由来:有一功能P1,由类A完毕。现须要将功能P1进行扩展,扩展后的功能为P,当中P由原有功能P1与新功能P2组成。新功能P由类A的子类B来完毕,则子类B在完毕新功能P2的同一时候,有可能会导致原有功能P1发生问题。
解决方式:当使用继承时,遵循里氏替换原则。类B继承类A时,除加入新的方法完毕新增功能P2外,尽量不要重写父类A的方法,也尽量不要重载父类A的方法。
继承包括这样一层含义:父类中凡是已经实现好的方法(相对于抽象方法而言),实际上是在设定一系列的规范和契约,尽管它不强制要求全部的子类必须遵从这些契约,可是假设子类对这些非抽象方法随意改动,就会对整个继承体系造成破坏。而里氏替换原则就是表达了这一层含义。
继承作为面向对象三大特性之中的一个,在给程序设计带来巨大便利的同一时候,也带来了弊端。
比方使用继承会给程序带来侵入性,程序的可移植性减少。添加了对象间的耦合性,假设一个类被其它的类所继承。则当这个类须要改动时,必须考虑到全部的子类。而且父类改动后,全部涉及到子类的功能都有可能会产生故障。
举例说明继承的风险,我们须要完毕一个两数相减的功能,由类A来负责。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class A{
public int func1(int a, int b){
return a-b;
}
}
public class Client{
public static void main(String[] args){
A a = new A();
System.out.println("100-50="+a.func1(100, 50));
System.out.println("100-80="+a.func1(100, 80));
}
}
|
执行结果:
100-50=50
100-80=20
后来,我们须要添加一个新的功能:完毕两数相加,然后再与100求和,由类B来负责。即类B须要完毕两个功能:
- 两数相减。
- 两数相加,然后再加100。
因为类A已经实现了第一个功能,所以类B继承类A后,仅仅须要再完毕第二个功能就能够了,代码例如以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
classBextendsA{
publicintfunc1(inta,intb){
returna+b;
}
publicintfunc2(inta,intb){
returnfunc1(a,b)+100;
}
}
publicclassClient{
publicstaticvoidmain(String[]args){
Bb=newB();
System.out.println("100-50="+b.func1(100,50));
System.out.println("100-80="+b.func1(100,80));
System.out.println("100+20+100="+b.func2(100,20));
}
}
|
类B完毕后,执行结果:
100-50=150
100-80=180
100+20+100=220
我们发现原本执行正常的相减功能发生了错误。原因就是类B在给方法起名时无意中重写了父类的方法,造成所有执行相减功能的代码所有调用了类B重写后的方法。造成原本执行正常的功能出现了错误。在本例中,引用基类A完毕的功能。换成子类B之后,发生了异常。
在实际编程中,我们经常会通过重写父类的方法来完毕新的功能,这样写起来尽管简单。可是整个继承体系的可复用性会比較差,特别是运用多态比較频繁时,程序执行出错的几率很大。假设非要重写父类的方法,比較通用的做法是:原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉,採用依赖、聚合,组合等关系取代。
里氏替换原则通俗的来讲就是:子类能够扩展父类的功能。但不能改变父类原有的功能。它包括下面4层含义:
- 子类能够实现父类的抽象方法,但不能覆盖父类的非抽象方法。
- 子类中能够添加自己特有的方法。
- 当子类的方法重载父类的方法时,方法的前置条件(即方法的形參)要比父类方法的输入參数更宽松。
- 当子类的方法实现父类的抽象方法时。方法的后置条件(即方法的返回值)要比父类更严格。
看上去非常不可思议,由于我们会发如今自己编程中经常会违反里氏替换原则,程序照样跑的好好的。
所以大家都会产生这种疑问,假如我非要不遵循里氏替换原则会有什么后果?
后果就是:你写的代码出问题的几率将会大大添加。
设计模式六大原则(2):里氏替换原则(Liskov Substitution Principle)的更多相关文章
- IOS设计模式的六大设计原则之里氏替换原则(LSP,Liskov Substitution Principle)
定义 里氏替换原则的定义有两种,据说是由麻省理工的一位姓里的女士所提出,因此以其名进行命名. 定义1:如果对一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1所定义的程序P中在o1全都替换 ...
- Java设计模式(4:里氏替换原则和合成复用原则详解
一.里氏替换原则 如果说实现开闭原则的关键步骤就是抽象化,那么基类(父类)和子类的继承关系就是抽象化的具体实现,所以里氏替换原则就是对实现抽象化的具体步骤的规范.即:子类可以扩展基类(父类)的功能,但 ...
- [设计模式]<<设计模式之禅>>关于里氏替换原则
在面向对象的语言中,继承是必不可少的.非常优秀的语言机制,它有如下优点:● 代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性:● 提高代码的重用性:● 子类可以形似父类,但又异于父类,“龙 ...
- 设计模式课程 设计模式精讲 3-10 里氏替换原则coding
1 代码演练 1.1 继承关系判别(是否是真正意义的继承) 1.2 入参控制 1.3 出参控制 1 代码演练 1.1 继承关系判别(是否是真正意义的继承)(其实我觉得这个例子有点牵强) 1.1.1 反 ...
- Java设计原则之里氏替换原则
里氏代换原则由2008年图灵奖得主.美国第一位计算机科学女博士Barbara Liskov教授和卡内基·梅隆大学Jeannette Wing教授于1994年提出.其严格表述如下:如果对每一个类型为S的 ...
- 深入理解JavaScript系列(8):S.O.L.I.D五大原则之里氏替换原则LSP
前言 本章我们要讲解的是S.O.L.I.D五大原则JavaScript语言实现的第3篇,里氏替换原则LSP(The Liskov Substitution Principle ). 英文原文:http ...
- 北风设计模式课程---里氏替换原则(Liskov Substitution Principle)
北风设计模式课程---里氏替换原则(Liskov Substitution Principle) 一.总结 一句话总结: 当衍生类能够完全替代它们的基类时:(Liskov Substitution P ...
- 【C#设计模式】里氏替换原则
今天,我们再来学习 SOLID 中的"L"对应的原则:里式替换原则. 里氏替换原则 里氏替换原则(Liskov Substitution Principle):派生类(子类)对象能 ...
- [OOD]违反里氏替换原则的解决方案
关于OOD中的里氏替换原则,大家耳熟能祥了,不再展开,可以参考设计模式的六大设计原则之里氏替换原则.这里尝试讨论常常违反的两种形式和解决方案. 违反里氏替换原则的根源是对子类及父类关系不明确.我们在设 ...
- C# 实例解释面向对象编程中的里氏替换原则
在面向对象编程中,SOLID 是五个设计原则的首字母缩写,旨在使软件设计更易于理解.灵活和可维护.这些原则是由美国软件工程师和讲师罗伯特·C·马丁(Robert Cecil Martin)提出的许多原 ...
随机推荐
- Python类的继承演示样例
class Pet: __name = "" def __init__(self, name): self.__name = name def bark(self): return ...
- mac 下搭建 Android 开发环境
因工作需要,要在mac 下搭建 Android 开发环境.谷歌.度娘了好久,没有找个一个完整又系统的方法,很是苦恼.最终,皇天不负有心人,找到了下面这篇文档,结合亲身体验,特此记录.也为有这方面需求的 ...
- BZOJ 1036: [ZJOI2008]树的统计Count( 树链剖分 )
树链剖分... 不知道为什么跑这么慢 = = 调了一节课啊跪.. ------------------------------------------------------------------- ...
- sed学习笔记整理
1.sed简介 sed (Stream Editor)是一种在线编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处 ...
- 浙江大学2015年校赛B题 ZOJ 3861 Valid Pattern Lock
这道题目是队友写的,貌似是用暴力枚举出来. 题意:给出一组数,要求这组数在解锁的界面可能的滑动序列. 思路:按照是否能够直接到达建图,如1可以直接到2,但是1不能直接到3,因为中间必须经过一个2. 要 ...
- POJ 2479 不相交最大子段和
题目意思还是很好理解的,在一个数列中,找出不相交的两个子串使得其和最大. 解题思路: 对于每个i来说,求出[0 ~ i - 1] 的最大子段和以及[i ~ n - 1]的最大子段和,在加起来,求最大的 ...
- 【集训笔记】【大数模板】特殊的数 【Catalan数】【HDOJ1133【HDOJ1134【HDOJ1130
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3324 http://blog.csdn.net/xymscau/artic ...
- RunLoop学习总结
开始 很久之前就看了一次YY的文章,没看懂.后来又看了sunny的视频和叶孤城的直播的视频,找了很多资料,对RunLoop也越来越清晰,然后又看了两三次YY的文章,虽然还没完全看懂,不得不说写的非常好 ...
- socket通信技术介绍
[-] 网络中进程之间怎样通信 什么是Socket socket一词的起源 socket的基本操作 socket函数 bind函数 网络字节序与主机字节序 listenconnect函数 accept ...
- GREENPLUM简单介绍
原帖:http://www.itpub.net/thread-1409964-1-1.html 什么是GREENPLUM? 对于非常多IT人来说GREENPLUM是个陌生的名字.简单的说它就是一个与O ...