Liskov Substitution Principle
里氏替换原则,OCP作为OO的高层原则,主张使用“抽象(Abstraction)”和“多态(Polymorphism)”将设计中的静态结构改为动态结构,维持设计的封闭性。“抽象”是语言提供的功能。“多态”由继承语义实现。
LSP:
1.概述: 派生类(子类)对象能够替换其基类(父类)对象被调用
2.概念:
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。(源自百度百科)
3.子类为什么可以替换父类的位置?:
当满足继承的时候,父类肯定存在非私有成员,子类肯定是得到了父类的这些非私有成员(假设,父类的的成员全部是私有的,那么子类没办法从父类继承任何成员,也就不存在继承的概念了)。既然子类继承了父类的这些非私有成员,那么父类对象也就可以在子类对象中调用这些非私有成员。所以,子类对象可以替换父类对象的位置。
4.里氏代换原则优点:
需求变化时,只须继承,而别的东西不会改变。由于里氏代换原则才使得开放封闭成为可能。这样使得子类在父类无需修改的话就可以扩展。
LSP的原定义比较复杂,我们一般对里氏替换原则 LSP的解释为:子类对象能够替换父类对象,而程序逻辑不变。
里氏替换原则有至少以下两种含义:1. 里氏替换原则是针对继承而言的,如果继承是为了实现代码重用,也就是为了共享方法,那么共享的父类方法就应该保持不变,不能被子类重新定义
子类只能通过新添加方法来扩展功能,父类和子类都可以实例化,而子类继承的方法和父类是一样的,父类调用方法的地方,子类也可以调用同一个继承得来的,逻辑和父类一致的方法,这时用子类对象将父类对象替换掉时,当然逻辑一致,相安无事。
2. 如果继承的目的是为了多态,而多态的前提就是子类覆盖并重新定义父类的方法,为了符合LSP,我们应该将父类定义为抽象类,并定义抽象方法,让子类重新定义这些方法,当父类是抽象类时,父类就是不能实例化,所以也不存在可实例化的父类对象在程序里。也就不存在子类替换父类实例时逻辑不一致的可能。
不符合LSP的最常见的情况是,父类和子类都是可实例化的非抽象类,且父类的方法被子类重新定义,这一类的实现继承会造成父类和子类间的强耦合,也就是实际上并不相关的属性和方法牵强附会在一起,不利于程序扩展和维护。
如何符合LSP?总结一句话 —— 就是尽量不要从可实例化的父类中继承,而是要使用基于抽象类和接口的继承。
https://www.zhihu.com/question/27191817
在知识表示、面向对象程序设计与面向对象设计的领域里,is-a(英语:subsumption,包含架构)指的是类的父子继承关系,例如类D是另一个类B的子类(类B是类D的父类)。
中文名 Is-a 外文名subsumption 实 质 指的是类的父子继承关系 例 子 类D是另一个类B的子类
换句话说,通常"Dis aB"(B把D包含在内,或是D被包含在B内)指的是,概念体D物是概念体B物的特殊化,而概念体B物是概念体D物的一般化。举例来说,水果是苹果、橘子、芒果与其他水果的一般化。
在面向对象程序设计里,is-a类关系是在继承概念的背景之下所形成的。有一说法是,对于所有水果来说,苹果继承(英语:inherit)所有的属性,就像是肉质多的水果包住种子般。
is-a与has-a两者是不同的对比,是以整体-附属阶层关系所组成的。也可以是instance-of的对比:请参考型态与个例的区别。
在真实世界里设计一个模型时(例如计算机程序),尤其是物件与它的下一层从属物件,在has-a与is-a两者的关系上容易产生概念上的错误。
原文地址:https://www.cnblogs.com/softidea/p/9112412.html