设计模式六大原则(二):里氏替换原则(Liskov Substitution Principle)
里氏替换原则(LSP)由来:
最早是在 妖久八八 年, 由麻神理工学院得一个女士所提出来的。
定义:
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来负责:
class Program
{
static void Main(string[] args)
{
B b = new B();
Console.WriteLine("100+20={0}",b.plus(, ));
Console.WriteLine("100-20={0}",b.reduce(, ));
Console.ReadKey();
}
} public class A
{
public int plus(int a, int b)
{
return a + b;
} public int reduce(int a, int b)
{
return a - b;
}
} public class B : A
{
public new int reduce(int a, int b)
{
return a - b + ;
}
}
后来, 我们增加了一个新功能, 要求相减在加上100, 由B类完成该功能。
我们发现原本运行正常的相减功能发生了错误。原因就是类B在给方法起名时无意中重写了父类的方法,造成所有运行相减功能的代码全部调用了类B重写后的方法,
造成原本运行正常的功能出现了错误。在本例中,引用基类A完成的功能,换成子类B之后,发生了异常。
在实际编程中,我们常常会通过重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差,特别是运用多态比较频繁时,
程序运行出错的几率非常大。如果非要重写父类的方法,比较通用的做法是:原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉,采用依赖、聚合,组合等关系代替。
PS: 通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。
- 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
- 子类中可以增加自己特有的方法。
- 当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
- 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。
设计模式六大原则(二):里氏替换原则(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)提出的许多原 ...
随机推荐
- 轻松学习之Linux教程四 神器vi程序编辑器攻略
本系列文章由@超人爱因斯坦出品,转载请注明出处. 文章链接: http://hpw123.net/a/Linux/Linuxjichu/2014/1026/93. ...
- 基于matlab的音频波形实时採集显示 v0.1
robj = audiorecorder(44100,16,1); %设置採样频率.採样位数.通道数 recordblocking(robj,1); %採集初步数据(1s长度) rdata = get ...
- Redis封装之String
RedisBase类 /// <summary> /// RedisBase类,是redis操作的基类,继承自IDisposable接口,主要用于释放内存 /// </summary ...
- SOAPUI使用
简介:在开发接口的时候每次验证接口是否正确都需要手动写测试DEMO来验证,使用SOAPUI可以大大减少测试时间. 目录 1.SOPUI介绍... 1 2.SOAPUI使用... 1 2.1新建SOAP ...
- Unix/Linux环境下多一点不如少一点
正如很多人所知道的$PATH环境变量里存着一张目录列表,当用户要执行某一程序时,系统就会按照列表中的内容去查找该程序的位置.当程序名前不带点斜线 . / 时$PATH就会起作用. 对于普通用户和roo ...
- VNC CentOS Linux下VNC Server远程桌面配置详解
VNC概述 VNC (Virtual Network Console)是虚拟网络控制台的缩写.VNC 是一款优秀的远程控制工具软件,由著名的 AT&T 的欧洲研究实验室开发的.VNC 是在基于 ...
- DEDECMS教程:列表页缩略图随机调用
如果用过DEDECMS的朋友应该都知道,有些模板列表页面需要用到缩略图,调用内容中的缩略图可以使用系统自带的脚本调用第一张图片.但是,并不是我们所有的内容里都有图片,有时候第一张图片也不一定是适合尺寸 ...
- 休假结束,Linus重回内核开发岗位
在休假反省一个多月之后,Linus Torvalds 又回来了.10 月 22 日爱丁堡举行的欧洲开源峰会上,Linus Torvalds 将与内核维护者们碰头,这是他重新接管Linux内核开发的第一 ...
- mysql InnoDB加锁分析
文章转载自:http://www.fanyilun.me/2017/04/20/MySQL%E5%8A%A0%E9%94%81%E5%88%86%E6%9E%90/ 以下实验数据基于MySQL 5.7 ...
- C++ Primer笔记12_运算符重载_递增递减运算符_成员訪问运算符
1.递增递减运算符 C++语言并不要求递增递减运算符必须是类的成员.可是由于他们改变的正好是所操作对象的状态.所以建议设定为成员函数. 对于递增与递减运算符来说,有前置与后置两个版本号,因此.我们应该 ...