里氏代换原则
定义:里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。
目的:里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。
价值:里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
说实话,“任何基类可以出现的地方,子类一定可以出现”,这话太抽象了,我根本找不出另例子来证明,什么是符合这个原则的,什么是不符合这个原则的。
子类一定可以出现,从语言的基本要求角度来讲,这是必须的,面向对象中父类就是可以被子类替换的,那么这个要求针对的是啥?
是需求的层面,因为子类替换父类,在技术上一定是允许的,那么我们在设计上要加些什么样的限制来保证这一点呢。
一个一个的举例吧:
1.类作为函数的参数:函数(类)
这种情况,那对该函数的设计要求是:该函数不能处理个性的需求,也就是说,不应该去处理基类中某一类型所特有的机能,否则这个函数设计不合格。
对类的设计要求是:个性的东西一定要自己处理,不能公开。
2.类做未一个调用函数的对象:类.函数()
这种情况,对该函数的设计要求是,该函数必须处理的是共性的内容,个性的内容要用通过this指针去处理。

通过上面的分析,视乎有点眉目,但仍然感觉不太具体。
一.如下是一个类的设计

// 长方形
class Rectangle{private:int h;int w;
public:void setH(int value){h = value; }void setW(int vaule){w = vaule;}int getH(){return h;}int getW(){return w;}
};
// 正方形
class Square:public Rectangle{void set(int value){setH(value);setW(value);}
};

二.到这来应该是没有问题的,因为LSP是一个需求级别的设计要求。
现在假设有这么一个要求,保证长方形的宽度一定要大于高度。
函数如下:

class Clinet{public:void setRectangle(Rectangle* r){if(r->getW()<r->getH()){r->setW(r->getH()+1);}}
};

显然这里:设计部符合LSP的设计原则了。
那么问题出在哪里?就是Clinet的setRectangle的入参是正方形就出问题了。
怎么办呢?
三.修改设计,其实修改的方法有很多,只要能把问题解决掉就行。
方案1:对正 方形进行特殊处理

// 长方形
class Rectangle{private:int h;int w;
public:void setH(int value){h = value; }void setW(int vaule){w = vaule;}int getH(){return h;}int getW(){return w;}//设计变更virtual void setRectangle(){if(getW()<getH()){setW(getH()+1);}}
};
// 正方形
class Square:public Rectangle{void set(int value){setH(value);setW(value);}//设计变更virtual void setRectangle(){}
};
class Clinet{public:void setRectangle(Rectangle* r){//设计变更r->setRectangle();}
};

在好多人眼里,这种修改方案可能不是一个优雅的方案,但很实用,下面在看看更优雅一点的方案。
方案2:提取更高级别的抽象
// 四边形

class Quadrilateral{protected:int h;int w;
public:virtual void setH(int value)=0;virtual void setW(int vaule)=0;virtual int getH()=0;virtual int getW()=0;
};
// 长方形
class Rectangle: public Quadrilateral{public:virtual void setH(int value){h = value; }virtual void setW(int vaule){w = vaule;}virtual int getH(){return h;}virtual int getW(){return w;}
};
// 正方形
class Square:public Quadrilateral{private:void setSide(int value){h = w = value;    }
public:virtual void setH(int value){setSide(value); }virtual void setW(int vaule){setSide(vaule);}virtual int getH(){return h;}virtual int getW(){return w;}
};
class Clinet{public:void setRectangle(Rectangle* r){if(r->getW()<r->getH()){r->setW(r->getH()+1);}}
};//客户端调用
int main()
{cout<<"建造者模式演示\n";//看代码不用考虑以下内容int cin_a;cin>>cin_a;return 0;
}

总结
设计无非就是解决共性和个性的问题,LSP做为一个原则,其实我们即使不学这个原则,也不一定不会遵守这个原则,因为如果你真的做了一个不符合这个原则的设计,那么运行马上就会遇到问题。
解决好共性和个性,就一定是一好的设计,一个符合各种设计原则的设计。
对于LSP这个原则,我其实一直都是理解的云里雾里的,直到现在才把这个东西具体化,所以,我觉得什么抽象的东西都试着举例说明,要不然你永远不会有一个清晰的思路。

里氏代换原则 举例 分析相关推荐

  1. 里氏替换原则——举例说明Java设计模式中的里氏替换原则

    里氏替换原则--举例说明Java设计模式中的里氏替换原则 1. 前言 官方定义: 2. 举例说明 2.1 例子介绍 2.2 反例 2.2.1 类图说明 2.2.2 代码说明 2.2.3 测试 2.2. ...

  2. 设计原则(3)-里氏代换原则

    本文转自:http://www.cnblogs.com/guoshiandroid/archive/2010/06/14/1758047.html 里氏代换原则 法海捉拿白蛇新解  应用场景举例: & ...

  3. Android大话设计模式 第四章----里氏代换原则----法海捉拿白蛇新解

    应用场景举例: <白蛇传>是中国四大民间传说之一,妇孺皆知. 在大多数人的感觉和印象中,白蛇是一个善良痴情.知恩图报.温柔友善.美貌绝伦.冰雪聪明.明辨是非.救苦救难的活菩萨:而法海却是一 ...

  4. LSP (里氏代换原则)

    LSP (里氏代换原则) 编辑 本词条缺少 名片图,补充相关内容使词条更完整,还能快速升级,赶紧来 编辑吧! LSP是里氏代换原则的英文Liskov Substitution Principle的缩写 ...

  5. 面向对象——依赖倒转原则和里氏代换原则

    什么是依赖倒转原则 下面三个就是 高层模块不依赖低层模块 抽象不依赖细节 细节依赖抽象 为什么需要这个原则? 假设现在需要开发一个软件,其中某个功能需要和数据库进行操作 那么,马上能想到的方法是不是就 ...

  6. 面向对象设计原则实践:之四.里氏代换原则

    五.里氏代换原则(LSP--Liskov Substitution Principle) 1. 定义 a). 如果对每一个类型为S的对象o1,都有类型为T的对象o2, 使得以T定义的所有程序P在所有的 ...

  7. 设计模式-设计原则-开闭原则是目标,里氏代换原则是基础,依赖倒转原则是手段...

    开闭原则是目标,里氏代换原则是基础,依赖倒转原则是手段,它们相辅相成,相互补充,目标一致,只是分析问题时所站角度不同而已. 转载于:https://www.cnblogs.com/jiangtao12 ...

  8. 里氏代换原则C#详解

    看了一大堆的资料讲解关于里氏代换原则,在这里我想分享给大家. 下面这段话来自百度百科,是这么解释里氏代换原则的: 里氏代换原则(Liskov Substitution Principle LSP)是面 ...

  9. 里氏代换原则(Liskov Substitution Principle)

    作用 它指导我们如何正确地进行继承与派生,并合理地重用代码! 定义 子类型必须能够替换掉它们的父类型.并出现在父类能够出现的任何地方. 这个就是尽量用多态的方法编程,也就是GRASP模式中的多态. 如 ...

最新文章

  1. oracle 定时器时间分区_oracle分区表按时间自动创建
  2. xml python gb2312_使用Python处理XML格式数据的方法介绍
  3. 5. Binary Tree Postorder Traversal
  4. 解决IDEA修改已有项目为maven项目时目录结构被改变的问题
  5. 如何远程访问Jetson Xavier/TX2
  6. 视觉SLAM笔记(48) 局部地图
  7. Myeclipse学习总结(15)——Eclipse/MyEclipse中Maven项目常见问题解决汇总
  8. q语言 科学计数_3岁宝宝说话结巴,被诊断语言障碍,我用1招让孩子口齿清晰,打脸众人!...
  9. 百度图神经网络学习——day05:图神经网络进阶模型
  10. anylogic和java,基于Anylogic的Java代码入门教程
  11. VMwareWorkstation下载链接
  12. Pyinstaller的Spec文件用法
  13. Object.assign与vue $set
  14. 强大的 Python 信号库:blinker 入门教程
  15. 按键精灵什么是动态数组?如何使用动态数组?(新手进阶)
  16. Java-小游戏-炸弹人-课程设计-搜索算法
  17. base64字符串实现下载文件
  18. javascript之活灵活现的Array
  19. android miui悬浮按钮,如何开启MIUI 8悬浮球 MIUI8悬浮球用法教程
  20. Redis启动、配置 及 常用命令

热门文章

  1. @sun.misc.Contended 伪共享
  2. 关于定时任务fixedRate和fixedDelay区别最简单的解释
  3. 英特尔酷睿 i9-11900K 首发评测优势分析,新架构Cypress Cove较上代性能提高19%
  4. Android学习路线的归纳总结,绝对干货!
  5. 在 Python 字典中按值查找键
  6. 微信小程序毕业设计 基于微信电影播放小程序系统开题报告
  7. 艾美捷CD8α体内抗体参数说明化学性质
  8. Vue路由-Router搭建以及简单使用
  9. Seq2Seq,Seq2Seq模型使用技巧
  10. Windows临时端口不够用导致TCP连接失败的问题