一、Abstract Class 与 Interface 的构造

抽象类 Abstract Class

<?php
abstract class A {
abstract public function method1();
abstract public function method2();
public function method3() {
//... code ...
}
}
?>

接口 Interface

<?php
interface B {
public function method4();
public function method5();
}
?>

可以看到,Abstract Class 中可以有抽象函数(method1,method2),也可以有具体的函数实现(method3),而 Interface 中只能定义函数而不能有实现(method4,method5)。显然,如果一个抽象类中的函数全部是抽象函数,那么这个抽象类就退化成了接口。不过要注意的是

  • PHP 和 Java 一样,一个 Class 只能继承一个 Abstract Class,但可以实现多个 Interface。这即是所谓的单一继承体系,也就是子类别只能继承一个父类别;一个父类别则可以被多个子类别所继承。据说在 Python 中是可以多重继承的。
  • 在 Abstract Class 中可以声明属性成员变量(attribute),而 Interface 不可以。

二、举例

下面的例子可以帮助我们从另一个层面:Abstract Class 和 Interface 所反映出的设计理念,来分析一下二者的本质区别。

假设我们要定义一个关于“门”的 Class,门有“开”和“关”两个动作。此时我们既可以用 Abstract Class 也可以用 Interface 来描述这个抽象概念——

抽象类 Abstract Class

<?php
abstract class Door {
abstract public function open();
abstract public function close();
}
?>

接口 Interface

<?php
interface Door {
public function open();
public function close();
}
?>

在 Abstract Class 中并没有实现开门和关门方法,因为有的门可以用钥匙打开,有的门用密码打开,还有的门可以用指纹打开,这些具体方法就交给子类继承去实现。在这样看上去 Abstract Class 和 Interface 二者的使用没有太大差别。

现在如果定义一种具有“报警”功能的门,Abstract Class 和 Interface 描述类似——

抽象类 Abstract Class

<?php
abstract class Door {
abstract public function open();
abstract public function close();
abstract public function alarm();
}
class AlarmDoor extends Door {
public function open() {
//...
}
public function close() {
//...
}
public function alarm() {
//...
}
}
?>

接口 Interface

<?php
interface Door
{
public function open();
public function close();
public function alerm();
}
class AlarmDoor implements Door {
public function open() {
//...
}
public function close() {
//...
}
public function alarm() {
//...
}
}
?>

很明显上面的做法是不对的。它在定义中把 Door 本身固有的开门、关门的行为方法和另外一个概念“报警器”的行为方法混在了一起。有的门可以报警,而有的门可能没有报警功能;而会报警的门也可能多种多样(钥匙开门,刷卡开门等等)。我们必须将报警行为单独定义到另一个对象中,那么就有 3 种方式:

  • 门和报警器都用 abstract class 方式定义;
  • 门和报警器都用 interface 方式定义;
  • 一个使用 abstract class 方式定义,另一个使用 interface 方式定义。

由于 PHP 中子类只可继承自一个 Abstract Class,而且 Abstract Class 不支持多重继承(abstract class cannot extend abstract class),所以第一种方式显然不行。而第二种方式则没有能够正确的揭示我们的设计意图,也就是没有反映出 AlarmDoor 在概念本质上是 Door,同时它有具有报警功能。所以对于 Door 这个概念,我们应该采取 Abstract Class 方式来定义,AlarmDoor 继承自 Door,而报警概念通过 Interface 方式定义。

<?php
abstract class Door {
abstract function open();
abstract function close();
}
interface Alarm {
function alarm();
}
class AlarmDoor extends Door implements Alarm {
public function open() {
//...
}
public function close() {
//...
}
public function alarm() {
//...
}
}
?>

这样的实现基本上正确地反映了我们的设计意图。接口是可以多重继承的,子类也可以实现多个接口。这样就使得我们可以继续扩展门的功能,比如给门再装个摄像头……

三、结论

当我们使用 Abstract Class 的时候,我们应该定义一类对象的属性,即描述它 是什么。而 Interface 则类似于插件,侧重于提供附加的能力,约定它 能做什么

php Abstract 抽象类 与 Interface的的更多相关文章

  1. Java abstract 抽象类 和interface接口的异同点

    abstract 抽象类 和interface接口的异同点 相同点: 抽象类和接口都不能实例化,他们都位于继承树顶端,被其他类实现和继承 都可以包含抽象方法,实现接口或者继承抽象类的非抽象类(普通类) ...

  2. abstract抽象类和interface接口

    一.抽象类 1.抽象类不能实例化,因为有抽象方法未实现 2.可以被抽象类或非抽象类继承 3.但不是只能被继承,还可以直接拿来使用的,当然,这个使用是拿来声明,反例如下: public abstract ...

  3. Java:抽象类abstract和接口Interface

    一.抽象类:abstract 抽象类就是为了继承而存在的,如果你定义了一个抽象类,却不去继承它,那么等于白白创建了这个抽象类,因为你不能用它来做任何事情.对于一个父类,如果它的某个方法在父类中实现出来 ...

  4. JAVA的abstract修饰符 && 接口interface用法 && 抽象类和interface的差别

    abstract修饰符可以修饰类和方法. (1)abstract修饰类,会使这个类成为一个抽象类,这个类将不能生成对象实例,但可以做为对象变量声明的类型(见后面实例),也就是编译时类型.抽象类就相当于 ...

  5. 《Beginning Java 7》 - 7 - abstract class 抽象类 和 interface 接口

    1. 抽象类: 为什么用抽象类: 一些 generic 的类本身并没有现实意义,所以不需要被实例化.比如动物,自然界没有动物这个物种,但却有无数的继承自动物的物种,那么动物本身可以是一个抽象类. 抽象 ...

  6. Java abstract class 和 interface 的区别

    Java abstract class 和 interface 的区别 1. abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制 2. 以Door的抽象概 ...

  7. 深入理解abstract class和interface(转)

    原文地址 深入理解abstract class和interface java提高篇(四)-----抽象类与接口

  8. abstract class和interface 知多少!!!

    1.相同点   A. 两者都是抽象类,都不能实例化.   B. interface实现类及abstrct class的子类都必须要实现已经声明的抽象方法. 2. 不同点   A. interface需 ...

  9. 11)Java abstract class 和 interface

    abstract class 和 interface 的区别        含有abstract修饰符的class即为抽象类,abstract 类不能创建实例对象.含有abstract方法的类必须定义 ...

随机推荐

  1. Leetcode春季活动打卡第三天:面试题 10.01. 合并排序的数组

    Leetcode春季活动打卡第三天:面试题 10.01. 合并排序的数组 Leetcode春季活动打卡第三天:面试题 10.01. 合并排序的数组 思路 这道题,两个数组原本就有序.于是我们采用双指针 ...

  2. 【剑指offer】27. 二叉树的镜像

    剑指 Offer 27. 二叉树的镜像 知识点:二叉树:递归:栈 题目描述 请完成一个函数,输入一个二叉树,该函数输出它的镜像. 示例 输入:root = [4,2,7,1,3,6,9] 输出:[4, ...

  3. 简单快速安装Apache+PHP+MySql服务环境(一)

    由于自己只是普通的coder,对于服务器的操作不是很熟悉,在网上找了很多关于PHP和apache服务器环境搭建的帖子,不过都不尽相同,尤其是编译安装更是看的云里雾里的,所以选择了一种比较简单的方式进行 ...

  4. 使用Angular CDK实现一个Service弹出Toast组件

    在Angular中,官方团队在开发Material组件库的同时,顺手做了一套Component dev kit,也就是在Angular世界中大名鼎鼎的CDK,这套工具包提供了非常多的前端开发的通用功能 ...

  5. SpringBoot时代背景

    微服务 James Lewis Martin Fowler 2014年提出微服务完整概念,https://martinfowler.com/microservices/ In short, the m ...

  6. Git,Linux,Ubuntu,Tmux的常用命令

    常用的连接 Git命令 廖雪峰的Git教程 Git常用命令 ubuntu16.04之GitHub入门教程 Linux相关 tmux命令 Ubuntu常用命令速查手册 Linux 命令大全 其它工具 M ...

  7. K-Fold 交叉验证

    转载--原文地址 www.likecs.com 1.K-Fold 交叉验证概念 在机器学习建模过程中,通行的做法通常是将数据分为训练集和测试集.测试集是与训练独立的数据,完全不参与训练,用于最终模型的 ...

  8. docker报错Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

    docker报错Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon run ...

  9. JIPB | 两篇连发:华中农大黄俊斌团队报道二羟基异丁酰化调控稻曲病菌致病新机制

    水稻是我国重要的粮食作物,稻曲病是水稻三大病害之一,不仅造成稻米产量损失,更重要的是稻曲球中的稻曲菌素的毒性和致畸作用,给人畜健康带来严重威胁.病原菌对植物的侵袭是由病原菌的毒力和植物免疫系统相互作用 ...

  10. PHP-Audit-Labs-Day2 - filter_var函数缺陷

    目录 分析 示例 payload 修复建议 Day02-CTF题解 参考链接 分析 先看源码 // composer require "twig/twig" require 've ...