替换原则由MIT计算机科学实验室的Liskov女士在1987年的OOPSLA大会上的一篇文章中提出,主要阐述有关继承的一些原则,故称里氏替换原则。

2002年,Robert C.Martin出版了一本名为《Agile Software Development Principles Patterns and Practices》的书,在书中他把里氏替换原则最终简化成一句话:“Subtypes must be substitutable for their base types”(子类必须能够替换成它们的基类。)
 
1.LSP的内容
里氏替换原则(Liskov Substitution Principle, LSP)的定义和主要思想如下:由于面向对象编程技术中的继承在具体的编程中过于简单,在许多系统的设计和编程实现中,我们并没有认真地、理性地思考应用系统中各个类之间的继承关系是否合适,派生类是否能正确地对其基类中的某些方法进行重写等问题。因此经常出现滥用继承或者错误地进行了继承等现象,给系统的后期维护带来了不少麻烦。这就需要我们有一个设计原则来遵循,它就是替换原则。
LSP指出:子类类型必须能够替换掉它们的父类型、并出现在父类能够出现的任何地方。它指导我们如何正确地进行继承和派生,并合理地重用代码。此原则认为,一个软件实体如果使用一个基类的话,那么一定适用于其子类,而且这根本不能察觉出基类对象和子类对象的区别。想一想,是不是和多态的概念比较像?
2.LSP主要是针对继承的设计原则
因为继承与派生是OOP的一个主要特性,能够减少代码的重复编程实现,从而实现系统中的代码复用,但是如何正确地进行继承设计和合理地应用继承机制呢?
这就是LSP所要解决的问题:
如何正确地进行继承方面的设计?
最佳的继承层次如何获得?
怎么样避免所设计的类层次陷入不符合OCP原则的状况?
那如何遵守该设计原则呢?
1)父类的方法都要在子类中实现或者重写,并且派生类只实现其抽象类中声明的方法,而不应当给出多余的方法定义或实现
2)在客户端程序中只应该使用父类对象而不应当直接使用子类对象,这样可以实现运行期绑定(动态多态)。
如果A、B两个类违反了LSP的设计,通常的做法是创建一个新的抽象类C,作为两个具体类的超类,奖A和B的共同行为移动到C中,从而解决A和B的行为不完全一致的问题。
不过PHP对LSP的支持并不好,缺乏向上转型等概念,只能通过一些曲折的方法实现。对于这个原则,这里就不细讲了。
 
下面给出一个缓存的实现接口,用抽象类做基类,遵循LSP实现其设计。

<?php
abstract class Cache
{
/**
* 设置一个缓存变量
* @param $key 缓存key
* @param $value 缓存内容
* @param int $expire 缓存时间(秒)
* @return boolean 是否缓存成功
*/
public abstract function set($key, $value, $expire = 60); /**
* 获取一个已经缓存的
* @param $key 缓存key
* @return mixed 缓存内容
*/
public abstract function get($key); /**
* 删除一个已经缓存的变量
* @param $key 缓存key
* @return boolean 是否删除成功
*/
public abstract function del($key); /**
* 删除全部缓存变量
* @return boolean 是否删除成功
*/
public abstract function delAll(); /**
* 检测是否存在对应的缓存
* @param $key 缓存key
* @return boolean 是否存在
*/
public abstract function has($key);
}
如果现在要求实现文件、memcache、accelerator等各种机制下的缓存,只需要继承这个抽象类并实现其抽象方法即可。
LSP中代码的不仅仅是功能,还名手语意。试思考:白马可以代换马,而牛同样作为劳动力,可代换马否?高跟鞋也是鞋子,男人穿高跟鞋又是否能接受?

最新文章

  1. ***PHP 数组排序 +php二维数组排序方法(PHP比较器)
  2. Java Web页面跳转
  3. jack报错
  4. 如果在安装32位oracle 客户端组件时的情况下以64位模式运行,将出现问题
  5. po 和 mo 的互相转换
  6. linux命令:find
  7. GooglePlay - 文件上传限制的扩展
  8. Spring中报&quot;Could not resolve placeholder&quot;的解决方案
  9. ES6模板字符串【${}配合反单引号一起用】
  10. java 通过jmx获取active mq队列消息
  11. Azure Load Balancer : 动态扩展
  12. Express static 托管静态文件 理解
  13. Android学习:ActionBar活动条
  14. odoo开发笔记 -- 搜索视图继承扩展
  15. 集美大学1414-团队作业2:需求分析&amp;原型设计分数发布
  16. LINUX内核分析第五周学习总结——扒开应用系统的三层皮(下)
  17. Ubuntu系统安装,适用于14.04,16.04和17.10
  18. jquery使用js的一些疼处
  19. WCF系列教程之WCF服务协定
  20. 并发包CallableAndFuture

热门文章

  1. 关于this的指向
  2. 使用spring代码中控制事务
  3. mybatis批量更新报错badsql
  4. Unity3D编辑器扩展(五)——常用特性(Attribute)以及Selection类
  5. Centos7配置hadoop伪分布式
  6. HTML5中input标签有用的新属性
  7. 当padding/margin的取值形式为百分比时。。。。。
  8. 面向对象一 OOP与类
  9. FPGA开发随笔汇总
  10. 《HTTP权威指南》5-Web服务器