如果对于每个类型是S的对象o1都存在一个类型为T的对象o2,能是操作T类型的程序P在用o2替换o1时行为保持不变,我们就可以将S称为T的子类型。
里氏替换原则:就是一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别。也就是说,在软件里面,把父类替换成它的子类,程序的行为没有变化。
假设我们有一个License的类,其结构如图所示。该类有一个名为caleFee()的方法,该方法将由Billing应用程序来调用。而License类有两个子类型:PersonalLicense与BusinessLicence,这两个类会用不同的算法来计算授权费用。这是符合LSP原则的,Billing应用程序的行为并不依赖于其使用的任何一个衍生类。
如果在面向对象设计时,一个是鸟类,一个企鹅类,如果鸟是可以飞的,企鹅不会飞,那么企鹅是不是鸟? 黄鹂会飞,黄鹂继承鸟这个类有没有问题呢?
企鹅不能以鸟(会飞)的身份出现,而黄鹂是可以的。在Client中使用鸟类会飞这个特性的时候企鹅是不满足条件的,而用黄鹂去替换其父类的时候没有任何问题。
只有当子类可以替换掉父类,软件单位的功能不收影响的时候,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为。
LSP逐渐演变成了一种更广泛的、指导接口与其实现方式的设计原则。LSP适用于用户依赖一种接口,并且都期待实现改接口的类之间能具有可替代性。
策略模式的UML图与图1相似,策略模式封装一个算法簇,算法之间具有公共的接口和不同的实现,算法之间可以相互替换。