继承和多态

类的组合与继承

  • 假设我们有两个类,一个 person,另外一个是 family;在 family 类中我们创建 person 类中的对象,并且我们把这个对象视为 family 类的一个属性,并调用它的方法处理问题,那么这种复用方式也称为组合。
  • 类与类之间还有一种父与子的关系,子类可以继承父类的属性和方法,我们称之为继承。在继承里,子类拥有父类的属性和方法,同时子类也有自己的属性和方法。
<?php
class person{
public $name = 'Tom';
public $gender;
static $money = 10000;
public function __construct(){
echo '这里是父类',PHP_EOL;
} public function say(){
echo $this->name,"\t is ",$this->gender,"\r\n";
}
} class family extends person{
public $name;
public $gender;
public $age;
static $money = 1000;
public function __construct(){
parent::__construct();
echo '这里是子类',PHP_EOL;
} public function say(){
parent::say();
echo $this->name,"\t is \t",$this->gender,",and is \t ",$this->age,PHP_EOL;
} public function cry(){
echo parent::$money,PHP_EOL;
echo '% >_< %',PHP_EOL;
echo self::$money,PHP_EOL;
echo "(*^_^*)";
}
} $poor = new family();
$poor->name = 'Lee';
$poor->gender = 'female';
$poor->age = 25;
$poor->say();
$poor->cry();

返回结果

这里是父类
这里是子类
Lee is female
Lee is female,and is 25
10000
% >_< %
1000
(*^_^*)%
  • 组合和继承都是提高代码可重用行的手段。在设计对象模型时,可以按照语义识别类之间的组合关系和继承关系。

例如:

  • 继承是一种 “是,像” 的关系,组合则是一种 “需要” 的关系 【父亲和儿子应该是继承关系,父亲和家庭应该是组合关系 】
  • 组合偏重与和局部的关系,继承偏重与父与子的关系。
  • 从方法复用的角度考虑,如果两个类具有很多相同的代码和方法,我们就可以从这两个类中抽象出一个父类,提供公共方法,然后两个类作为子类,提供个性方法,这时继承更好。
  • 组合的限制很少,组合之间的类可以关系很小 (体现为复用代码),设置没有关系。

编程中

  • 继承和组合的取舍往往都不是这么直接明了,很难说出二者是 “像” 的关系还是需要的关系。甚至说把它拿到现实世界中建模,更加无法决定是继承还是组合的关系了。这时,它该如何办,有什么标准?这个标准就是:低耦合

低耦合

  • 耦合是一个软件结构内不同模块之间互联程度的度量,也就是不同模块之间的依赖关系。
  • 低耦合是指模块和模块之间,尽可能地使模块间独立存在;模块与模块之间的接口尽量少而简单。现代的面向对象的思想不强调为真实世界建模,变得更加理性化一些,把目标放在解耦上。

解耦

  • 目的是为了解除模块与模块之间的依赖。
  • 继承和组合二者在语义上难以区分,但是我们更倾向于使用组合。
  • 继承存在的问题:
    • 继承破坏封装性;(鸟类为父类,而鸭子和鸵鸟作为子类,它们却拥有飞翔的方法)
    • 继承是紧耦合的,使得子类和父类捆绑在一起。组合仅是通过唯一接口和外部进行通信,耦合度低于继承。
    • 继承扩展复杂,随着继承层数的增加和子类的增加,将涉及大量方法重写。使用组合,可以根据类型约束,实现动态组合,减少代码。
    • 不恰当的使用继承可能违反现实世界中的逻辑;

组合

<?php

class car{
public function addoil(){
echo "Add oil \r\n";
}
} class bmw extends car{
}
class benz{
public $car;
public function __construct(){
$this->car = new car();
} public function addoil(){
$this->car->addoil();
}
}
$bmw = new bmw();
$bmw->addoil();
$benz = new benz();
$benz->addoil();
  • 在创建组合对象时,组合需要一一创建局部对象,这一点程度上增加了一些代码,而继承不需要这一步,继承拥有父类的方法,可以直接使用

如何使用继承:

  • 精心设计专门用于被继承的类,继承树的抽象层应该比较稳定,一般不多于三层;
  • 对于不是专门用于被继承的类,禁止其被继承,也就是使用 final 修饰符。使用 final 修饰符即可防止重要方法被非法覆写,又能给编辑器寻找优化的机会;
  • 优先考了用组合关系提高代码的可重用性;
  • 子类是一直特殊的类型,而不只是父类的一个角色;
  • 子类扩展,而不是覆盖或者使父类的功能失效;
  • 底层代码多用组合,顶层 / 业务层代码多用继承。底层用组合可以提供效率,避免对象臃肿。顶层代码用继承可以提高灵活性,让业务使用更方便。

既要组合的灵活,又要继承的简洁

  • 多重继承,一个类可以同时继承多个父类,组合两个父类的功能;缺点:多重继承过于灵活,并且会带来 “零星问题”,故为其使用带来了不少困难,模型变得复杂起来。
  • traits php5.4 引入的新的语法结构,可以方便我们实现对象的扩展,是除 extend,implements 外的另外一种扩展对象的方式,traits 即可以使单继承模式的语言获得多重继承的灵活,又可以避免多重继承带来的种种问题

traits 的用法

  • 通过在类中使用 use 关键字声明要组合的 Trait 名称,而具体某个 Trait 的声明使用 trait 关键词,Trait 不能直接实例化
<?php
trait Drive {
public $carName = 'BMW';
public function driving() {
echo "driving {$this->carName}\n";
}
}
class Person {
public function age() {
echo "i am 18 years old\n";
}
}
class Student extends Person {
use Drive;
public function study() {
echo "Learn to drive \n";
}
}
$student = new Student();
$student->study();
$student->age();
$student->driving();
Learn to drive
i am 18 years old
driving BMW
  • Student 类通过继承 Person,有了 age 方法,通过组合 Drive,有了 driving 方法和属性 carName。

如果 Trait、基类和本类中都存在某个同名的属性或者方法,最终会保留哪一个呢

<?php
trait Drive {
public function hello() {
echo "hello 周伯通\n";
}
public function driving() {
echo "周伯通不会开车\n";
}
}
class Person {
public function hello() {
echo "hello 大家好\n";
}
public function driving() {
echo "大家都会开车\n";
}
}
class Student extends Person {
use Drive;//trait 的方法覆盖了基类Person中的方法,所以Person中的hello 和driving被覆盖
public function hello() {
echo "hello 新学员\n";//当方法或属性同名时,当前类中的方法会覆盖 trait的 方法,所以此处hello会覆盖trait中的hello
}
}
$student = new Student();
$student->hello();
$student->driving();
hello 新学员
周伯通不会开车
  • 当方法或属性同名时,当前类中的方法会覆盖 trait 的 方法,而 trait 的方法又覆盖了基类中的方法。

如果要组合多个 Trait,通过逗号分隔 Trait 名称:

use Trait1, Trait2;
<?php
trait Hello {
public function sayHello() {
echo "Hello 我是周伯通\n";
}
}
trait World {
use Hello;
public function sayWorld() {
echo "hello world\n";
}
abstract public function getWorld();
public function inc() {
static $c = 0;
$c = $c + 1;
echo "$c\n";
}
public static function doSomething() {
echo "Doing something\n";
}
}
class HelloWorld {
use World;
public function getWorld() {
return 'do you get World ?';
}
}
$Obj = new HelloWorld();
$Obj->sayHello();
$Obj->sayWorld();
echo $Obj->getWorld() . "\n";
HelloWorld::doSomething();
$Obj->inc();
$Obj->inc();
Hello 我是周伯通
hello world
do you get World ?
Doing something
1
2

语言中得多态

  • 多态准确的含义是:同一类的对象收到相同消息时,会得到不同的结果。而这个消息是不可预测的。多态:顾名思义,就是多种状态,也就是多种结果
  • 多态性是一种通过多种状态或阶段描述相同对象的编程方式。它真正的意义在于:实际开发中,只要关心一个接口或基类的编程,而不必关心一个对象所属于的具体类

案例

  • 通过判断传入的对象所属的类不同来调用其同名方法来实现 ’ 多态 ’
<?php
class employee{
protected function working(){
echo '本方法需要重载才能运行';
}
}
class teacher extends employee{
public function working(){
echo '教书';
}
}
class coder extends employee{
public function working(){
echo '敲代码';
}
}
function doprint($obj){
//get_class 获取当前对象调用的类名
if(get_class($obj)=='employee'){
echo 'Error';
}else{
$obj->working();
}
}
doprint(new teacher());
doprint(new coder());
doprint(new employee());
  • 通过接口实现多态
<?php
interface employee{
public function working();
}
class teacher implements employee{
public function working(){
echo '教书';
}
}
class coder implements employee{
public function working(){
echo '敲代码';
}
}
function doprint(employee $i){
$i->working();
}
$a=new teacher;
$b=new coder;
doprint($a);
doprint($b);
  • 在这段代码中,doprint 函数的参数为一个接口类型的变量,符合 ’ 同一类型,不同结果 ’ 这一条件,具备多态的一般特征。

总结

  • 多态指同一类对象在运行时的具体化。
  • php 语言是弱类型的,实现多态更简单,更灵活。
  • 类型转换不是多态。
  • php 中父类和子类看作 ’ 继父 ’ 和’ 继子 ’ 关系,他们存在继承关系,但不存在血缘关系,因此子类无法向上转型为父类,从而失去多态最典型的特征。
  • 多态的本质就是 if – else – ,只不过实现的层次不同。

看完就能掌握的PHP核心技术 - ​​​​​​​​面向对象的更多相关文章

  1. 一口气看完45个寄存器,CPU核心技术大揭秘

    序言 前段时间,我连续写了十来篇CPU底层系列技术故事文章,有不少读者私信我让我写一下CPU的寄存器. 寄存器这个太多太复杂,不适合写故事,拖了很久,总算是写完了,这篇文章就来详细聊聊x86/x64架 ...

  2. 看完它,你就全懂了十大Wifi芯片原厂!

    看完它,你就全懂了十大Wifi芯片原厂!   来源:全球物联网观察 概要:不知不觉中,WiFi几乎已攻占了整个世界.现在只要你上网,可能就离不开WiFi了. 2014年是物联网WiFi市场关键的转折期 ...

  3. 看完SQL Server 2014 Q/A答疑集锦:想不升级都难!

    看完SQL Server 2014 Q/A答疑集锦:想不升级都难! 转载自:http://mp.weixin.qq.com/s/5rZCgnMKmJqeC7hbe4CZ_g 本期嘉宾为微软技术中心技术 ...

  4. 在知乎上看到 Web Socket这篇文章讲得确实挺好,从头看到尾都非常形象生动,一口气看完,没有半点模糊,非常不错

    在知乎上看到这篇文章讲得确实挺好,从头看到尾都非常形象生动,一口气看完,没有半点模糊,非常不错,所以推荐给大家,非常值得一读. 作者:Ovear链接:https://www.zhihu.com/que ...

  5. 盘点国内程序员不常用的热门iOS第三方库:看完,还敢自称”精通iOS开发”吗?【转载】

    综合github上各个项目的关注度与具体使用情况,涵盖功能,UI,数据库,自动化测试,编程工具等类型,看完,还敢自称”精通iOS开发”吗? https://github.com/syedhali/EZ ...

  6. APP的缓存文件到底应该存在哪?看完这篇文章你应该就自己清楚了

    APP的缓存文件到底应该存在哪?看完这篇文章你应该就自己清楚了 彻底理解android中的内部存储与外部存储 存储在内部还是外部 所有的Android设备均有两个文件存储区域:"intern ...

  7. 视频1-14待JSP课程看完再练习

    视频1-14待JSP课程看完再练习 http://www.imooc.com/video/5555

  8. 看完这些,你就算得上既了解围棋又了解alphago了

    首先,我们要祝贺小李下出第78手的“神之一手”,这一手堪称前无古人后无来者,尤其是结合了阿尔法狗自暴自弃的表现.小李说过他的失败并不是人类的失败,同样,小李的胜利也只是属于他一人的胜利. 然而人类在围 ...

  9. 看完final的感受

    今天没课,(其实是有体育课的,去打了一会球就跑路了...)就在宿舍看world final ; 我去,老毛子真是好厉害,看的我目瞪口呆,哈喇子直流; 上交的大神好厉害,本来还以为上交要夺冠的,最后罚时 ...

随机推荐

  1. JavaScript动画实例:沿五角星形线摆动的小圆

    五角星形线的笛卡尔坐标方程式可设为: r=10+(3*sin(θ*2.5))^2  x=r*cos(θ) y=r*sin(θ)              (0≤θ≤2π) 根据这个曲线方程,在[0,2 ...

  2. 服务注册与发现【Eureka】- Eureka简介

    什么是服务治理 SpringCloud 封装了 Netflix 公司开发的 Eureka 模块来 实现服务治理. 在传统的rpc远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所 ...

  3. 多国正在遭遇新型勒索病毒Petya侵袭

    北京时间2017年6月27日晚,据外媒消息,多国正在遭遇 Petya 勒索病毒袭击,政府.银行.电力系统.通讯系统.企业以及机场都受到不同程度影响.请予关注,并做相应防范.相关事件描述及防范措施如下: ...

  4. twitch游戏直播(【国外】平台)如何绑定二次验证码_虚拟MFA?

    一般点账户名——设置——安全设置中开通虚拟MFA两步验证 具体步骤见链接 twitch游戏直播([国外]平台)如何绑定二次验证码_虚拟MFA? 二次验证码小程序于谷歌身份验证器APP的优势(更多见官网 ...

  5. 我把JVM的类加载器整理了一下

    前言 ​ 之前去面试的时候面试官问了我关于关于JVM性能调优的问题,由于自己之前公司的项目里自己没有接触到JVM性能调优的相关问题(感觉这些都是公司架构师考虑的问题),所有面试官问的时候自己一脸懵逼, ...

  6. jenkins集群(二)(master --> slave) -- allure自动化测试报告部署

    一.前提 1.环境 1)已经部署好了jenkins环境,包括jenkins的“全局工具配置”也配好了. 2.master与slave的简单的概念 1)master:jenkins部署所在的机器 2)s ...

  7. 基于jqgrid + ashx + nhibernate的分页

    因为我目前运维的是一个webform项目,项目中未用到分页的功能,我百度了很多文章也没有一篇是结合jqgrid + ashx + nhibernate的分页,可能是因为后台要请求ashx的原因,不像m ...

  8. CCNA - Part12 - 路由协议 (1) - 静态路由,动态路由 RIP

    路由器 在之前关于路由器的介绍中,我们知道它是网络互联的核心设备,用于连接不同的网络,在网络之间转发 IP 数据报.对于路由器来说,路由表是其内部最为重要的构成组件.当路由器需要转发数据时,就会按照路 ...

  9. 容器centos7安装部署ansible

    容器centos7安装部署ansible centos镜像版本及ansible版本 centos:centos7.5.1804 ansible:2.9.11 启动容器并进入容器 docker run ...

  10. PHP xml_set_notation_decl_handler() 函数

    定义和用法 xml_set_notation_decl_handler() 函数规定当解析器在 XML 文档中找到符号声明时被调用的函数. 如果成功,该函数则返回 TRUE.如果失败,则返回 FALS ...