重写方法时不调用父类方法是否违反Liskov原则?
好问题!咱们先把Liskov替换原则(LSP)的核心搞清楚,再拆解你的例子。
Liskov替换原则的核心是什么?
Liskov替换原则的本质是行为契约的一致性:子类必须遵守父类所定义的行为约定(不管是代码里显式写的,还是文档/业务逻辑隐含的)。简单说就是——任何使用父类对象的地方,替换成子类对象后,程序依然能正常运行,不会出现不符合预期的结果。
回到你的例子:是否违反LSP?
答案是:不一定,关键看子类重写的feed()是否遵守了父类feed()的行为契约,和是否调用super.feed()没有直接关系。
咱们分两种情况看:
🔹 符合LSP的场景
如果父类Animal的feed()契约是「给动物提供食物,满足其营养需求」,而子类Dog的feed()重写后,实现了狗专属的喂食逻辑(比如喂狗粮、调整喂食量),但最终依然完成了「喂食」这个核心行为——那不管你调不调用super.feed(),这都完全符合LSP。因为任何依赖Animal.feed()的代码,换成Dog后依然能达成“给动物喂食”的预期。🔹 违反LSP的场景
如果父类Animal的feed()隐含了额外的行为约定(比如「每次喂食后记录日志到数据库」),而子类Dog的feed()完全没做这件事,同时业务代码里有逻辑依赖“喂食日志被记录”这个行为——那这就违反了LSP。因为把Animal换成Dog后,原本依赖日志的逻辑会失效,出现不符合预期的结果。
关键结论
是否调用父类方法从来不是LSP的判断标准,核心是子类重写的方法有没有保持父类方法的行为契约。只要子类的行为和父类约定一致,哪怕完全重写逻辑不调用super,也没问题;反之,如果子类破坏了父类的行为约定,哪怕调用了super,也可能违反LSP。
举个极端反例:如果父类Animal.feed()的作用是「让动物吃饱」,而子类Dog.feed()改成了「清空动物的食盆」——那不管你调不调用super,这都明显违反LSP,因为它彻底颠覆了父类的行为预期。
内容的提问来源于stack exchange,提问作者user9159218

