1.定义:
继承必须确保超类所拥有的性质在子类中仍然成立
人话:子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。
2.抄一段实现说明
根据上述理解,对里氏替换原则的定义可以总结如下:
- 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
- 子类中可以增加自己特有的方法
- 当子类的方法重载父类的方法时,方法的前置条件(即方法的输入参数)要比父类的方法更宽松
- 当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的的输出/返回值)要比父类的方法更严格或相等.
3. 理解
抽象类提供的非抽象方法别动,抽象方法实现了.如果非得要重写一个已有类的实现方法那定义一个新的公共类(其实是一各新抽象)
示例:原有一个内容类输出的是微信图文内容,将别人的文章存储到自己的系统里面,中间会把外网资源比如图片转成自己的图片地址
现在新添加了一个内容子类抖音视频.但是sourceDeal方法没办法上传视频,得重写一下
错误的修改:如下,这时候其实sourceDeal的性质已经改变了.DouyinVideoContent类如果再诞生子类,sourceDeal方法和抽象类AContentsourceDeal的含义是不同的.而且不是不包含它的能力
<?php interface IContent{ /** * 获取内容 * */ function content() : array; } abstract class AContent implements IContent{ //原始数据 protected $oData; protected function __construct(array $oData) { $this->oData = $oData; } /** * 获取内容 * */ abstract function content():array; /** * 资源处理:上传远端云存储 * */ protected function sourceDeal($path){ //$rs = $api->remote($imgPath); 调用远端持久化 return ''; } } /** * 微信图文处理 * */ class WxImageTextContent extends AContent{ function content(){ $content = $this->oData; //一顿处理... //有一张图片 $img = ''; $img= $this->sourceDeal($img); //替换一下... return $content; } } /** * 抖音视频处理 * */ class DouyinVideoContent extends AContent{ function content(){ $content = $this->oData; //一顿处理... //有一段儿视频 $video = ''; $video= $this->sourceDeal($video); //替换一下... return $content; } /** * 资源处理:上传远端云存储 * */ protected function sourceDeal($path){ //$rs = $api->remote($imgPath); 调用远端持久化 //重写需要处理视频.原来都是图片 return ''; } }
可以接受的方式有两种:
(1)重写sourceDeal兼容上传图片和视频
/** * 抖音视频处理 * */ class DouyinVideoContent extends AContent{ function content(){ $content = $this->oData; //一顿处理... //有一段儿视频 $video = ''; $video= $this->sourceDeal($video); //替换一下... return $content; } /** * 资源处理:上传远端云存储 * */ protected function sourceDeal($path){ //$rs = $api->remote($imgPath); 调用远端持久化 //重写需要处理视频.原来都是图片 //如果是图片 //$this->imgDeal(); //如果是视频 //$this->>videoDeal(); return ''; } protected function imgDeal(){ } protected function videoDeal(){ } }
(2)定义新的继承结构,中间再加一层,重写sourceDeal.为之后的sourceDeal定义是可以上传图片和视频.
/** * 来一个抽象类扩展sourceDeal,这时扩容的能力被保存下来.之后的子类也可以用 * */ abstract class AContentWithSourceDeal extends AContent{ /** * 资源处理:上传远端云存储 * */ protected function sourceDeal($path){ //$rs = $api->remote($imgPath); 调用远端持久化 //重写需要处理视频.原来都是图片 //如果是图片 //$this->imgDeal(); //如果是视频 //$this->>videoDeal(); return ''; } protected function imgDeal(){ } protected function videoDeal(){ } }
(3)在(2)的基础上可以独立出sourceDeal的处理类,这时AContentWithSourceDeal没有混合太多其他的能力.比如imgDeal,videoDeal.
class SourceDealObj{ function run($path){ } protected function imgDeal(){ } protected function videoDeal(){ } } /** * * */ abstract class AContentWithSourceDeal extends AContent{ protected $sourceDealObj; protected function setSourceDealObj($sourceDealObj){ $this->sourceDealObj = $sourceDealObj; } /** * 资源处理:上传远端云存储 * */ protected function sourceDeal($path){ //$rs = $api->remote($imgPath); 调用远端持久化 //重写需要处理视频.原来都是图片 $source = $this->sourceDealObj->run($path); return $source; } }