里氏替换原则

在子类继承父类时,类中的方法需要保证与父类的行为预期一致

好的继承:

<?php

abstract class Animal
{
    public function makeSound()
    {
        echo 'Make some sound';
    }
}

class Cat extends Animal
{

    public function makeSound()
    {
        echo 'Meow~ Meow~';
    }
}

function makeAnimalSounds(Animal $animal)
{
    $animal->makeSound();
}

makeAnimalSounds(new Cat());

在子类覆写父类的方法时,与其行为预期表现一致,不会导致程序产生意外的错误。

<?php

abstract class Animal
{
    public function makeSound()
    {
        echo 'Make some sound';
    }
}

class Dog extends Animal
{
    public function makeSound()
    {
        throw new Exception("I can't make sound");
    }
}

function makeAnimalSounds(Animal $animal)
{
    $animal->makeSound();
}

makeAnimalSounds(new Dog());

子类的 makeSound() 方法返回值与父类不一致,容易产生意外的 Bug。

里氏替换原则最终的目的是「子类」可以完全替代「父类」,这就意味着子类的方法实现的功能要和父类一致。

换言之:子类的方法应该具有与父类相同的输入和输出,即使是 Bug,也要一模一样。

本作品采用《CC 协议》,转载必须注明作者和本文链接
悲观者永远正确,乐观者永远前行。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 5
wonders

可以把SOLID 都写一下 蹲一个 :joy:

6个月前 评论
MArtian (楼主) 6个月前

好吧,潜意识就是这么做的,跟着定义的返回类型来的。

6个月前 评论
  1. 子类和父类的输入输出需要一样, 首先你得有输入输出的类型声明,然后要求子类和父类的返回值类型相同就可以。
  2. 并不一定子类的所有方法的输入输出都必须和父类相同。 面向对象的封装特性,类通过 private 关键字隐藏业务逻辑的内部实现。 所以不管是父类和子类, private 方法外部都是访问不到的,都是这个类的内部逻辑, 它怎么写和别的类一点关系没有。
  3. 在写一个类之前可以先定义类的接口,接口中定义类有那些 public 方法以及类型声明,父类和子类都实现了这个接口,自然就遵守了里氏替换原则。 这样的好处就是方便依赖注入,laravel 服务提供者里面 接口绑定实现,然后用的时候直接从容器里拿接口的实现。 因为父类和子类都实现了同一个接口,返回值的类型一样。所以服务提供者那改接口绑定的实现,一般也不会出问题。 举个反例 比如 getName 方法父类返回的是字符串类型。 子类不遵循里氏替换原则瞎改,返回了一个Array , Array 既有昵称又有真实名称,如果业务逻辑有一个 if(UserManage::getName() == "雷军") {} 可能就会出问题。 反之如果遵守里氏替换原则, 这里起码不会出语法错误,
6个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!