六、里氏替换原则

2019-08-14  本文已影响0人  四月的谎言v5

里氏替换原则(Liskov Substitution Principle,LSP)

里氏替换原则是我认为其他几个设计原则中比较难以掌握一种,首先他的定义十分晦涩。

假如存在,一个类型T,和已经被实例的对象O

还存在,另一个类型T2,和已经被实例的对象O2

那么存在以下情况,将所有类型为T的对象O都替换成类型T2的对象O2,程序的行为没发生什么改变。

看到这一句话给我的第一个感觉是,这讲的一定是父子关系,这是第一点。

第二点,如果说即便替换了对象,方法的功能或者说行为没有改变,也就意味着子类只是对原有父类的功能进行了他独有的增强,本质还是做了相同事,例如父类做了跳高的行为,而子类只是穿上了弹簧鞋子,跳的更高了。本质上还是跳高,所以你替换成什么,都不会影响他原有的逻辑。

所以我们总结一下就是:子类可以扩展父类的功能,但是不能改变父类原有的功能。。

以下是我从找到的资料粘贴下来的说明,我觉得讲得很好。

1、子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。

2、子类中可以增加自己特有的方法。

3、当子类的方法重载父类的方法时,方法的前置条件(即方法的输入/入参)要比父类方法的输入参数更宽松。

4、当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的输出/返回值)要比父类更严格或相等。

之前讲开闭原则的时候留了一个坑,就是获取价格的时候。

public class TomatoEggDiscountFood extends TomatoEggFood {
    public TomatoEggDiscountFood(Integer id, String name, Double price) {
        super(id, name, price);
    }
    public Double getOriginPrice(){//这里其实违背了里氏替换法则,后会讲解,这里留个坑
        return super.getPrice();
    }
    public Double getPrice(){
        return super.getPrice() * 0.8;//修改的行为
    }
}

这里其实存在问题,虽然说我们为了获得打折后的炒蛋的价格,而去重写了父类的方法,但是我们可以发现,这里其实不适用于里氏替换法则,因为当我们将TomatoEggDiscountFood替换成TomatoEggFood的时候,getPrice的行为就变得奇怪了,因为钱涨了?虽然这都是属于付钱,但是你可以决定让我支付宝或者微信付款,但是你多收我钱是几个意思。所以这里付钱的行为你可以增强,但是具体付钱的金额,导致违背了里氏替换

解决这个方法很简单。我们别重写,额外定义我们自己独有的方法不就完了吗。

public class TomatoEggDiscountFood extends TomatoEggFood {
    public TomatoEggDiscountFood(Integer id, String name, Double price) {
        super(id, name, price);
    }
    public Double getDisCountinPrice(){//想获得打折,调用这个方法就可以了。
        return super.getPrice()*0.8;
    }
    public Double getPrice(){
        return super.getPrice();
    }
}

想替换的时候也不要紧,因为你的父类不可能点出getDisCountinPrice方法,所以也不需要担心会被替换的问题。

所以里氏替换的优点,我们也可以总结一下。

1、约束继承泛滥,开闭原则的一种体现。

2、加强程序的健壮性,同时变更时也可以做到非常好的兼容性,提高程序的维护性、扩展性。降低需求变更时引入的风险。

版权声明:本文为CSDN博主「PopCandier」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/CandyCCCation/article/details/88904701

上一篇下一篇

猜你喜欢

热点阅读