PHP强化之18 - 抽象类与接口

[toc]

一、abstract

1、抽象类
在实际开发中,我们可以有这样一种类,是其它类的父类,但是他本身并不需要去实例化,主要用途是用于让子类来继承,这样可以达到代码的复用,同时利于项目设计者去设计类。

  • 定义抽象类:
abstract class 类名{
  //属性
  //方法
}
  • 继承抽象类
class 类名 extends 抽象类
{
 
}

2、抽象方法

抽象方法不能有方法体。所谓没有方法体就是在方法声明的时候没有大括号以及其中的内容,而是直接声明时在方法名后加上分号结束。

  • 如:
abstract function 方法名();

3、注意

1)如果一个类使用了abstract来修饰,则该类就是抽象类(不能被实例化)。
2)抽象类可以没有抽象方法,同时还可以有实现了的方法。
3)一个类只要有abstract方法,则该类必须声明为abstract类。
4)抽象方法是作为子类方法重载的模板使用的,如果一个A类继承了一个抽象B类,则要求A类实现B类的所有抽象方法(除非A类也是抽象类)。
5)如果子类没有全部实现抽象类中的所有抽象方法,那么该子类也是一个抽象类,必须在 class 前面加上 abstract 关键字,并且不能被实例化。
6)抽象方法不能为private。

二、interface

1、简介

接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些方法写出来。

接口是更加抽象的抽象类,抽象类可以存在有方法体的方法,而接口里的所有方法都没有方法体。

接口体现了程序设计的多态和高内聚低偶合的设计思想。

2、定义接口类

interface A
{
    public function a();
    Public function b();
}

3、实现接口类

class X implements A
{
    public function a(){
    }
    public function a(){
    }
}

4、注意

1)不能去实例化一个接口。
2)接口中的所有方法都不能有方法体。
3)一个接口可以继承多个其它接口。
4)一个类可以实现多个接口(用逗号隔开)。
5)接口中可以有属性,但必须是常量,默认是public。
6)接口的方法必须都是public,默认public。(但将常量变量放在接口中违背了其作为接口的作用而存在的宗旨,也混淆了interface与类的不同价值。所以不建议)
7)一个类可以同时继承又实现某些接口。(extends子句应该在implements子句之前)
8)任何实现接口的类都要实现接口中所定义的所有方法。

三、Abstract Class与Interface的异同

1、 相同点:

1)两者都是抽象类,都不能实例化。
2)interface 实现类及 abstract class 的子类都必须要实现已经声明的抽象方法。

2、不同点:

1)interface需要实现,要用 implements ;而 abstract class 需要继承,要用 extends 。
2)一个类可以实现多个 interface ,但一个类只能继承一个abstract class。
3) interface 中的每一个方法都是抽象方法,实现类必须要实现;而 abstract class 的子类可以有选择地实现。
4)接口中的抽象方法前不用也不能加 abstract 关键字,默认隐式就是抽象方法,也不能加 final 关键字来防止抽象方法的继承;而抽象类中抽象方法前则必须加上 abstract 表示显示声明为抽象方法。
5)接口中的抽象方法默认是 public 的,也只能是 public 的;而抽象类中的抽象方法则可以用 public 或 protected 来修饰,但不能用 private 。

四、Interface经典实例

需求:
我需要从不同的源收集文本。(可以从远程URL读取HTML,可以读取流资源,也可以收集终端命令的输出)

1、定义Documentable接口

实现Documentable接口的任何类都必须实现接口的getId()方法与getContent()方法。

<?php
interface Documentable
{
    public function getId();
    public function getContent();
}

2、定义三种实现方式

定义以上接口的用处是,我们可以分开定义获取文档的类,而且能使用十分不同的实现方式。

1)定义HtmlDocument类

<?php
class HtmlDocument implements Documentable
{
    protected $url;
    public function __construct($url)
    {
        $this->url = $url;
    }
    public function getId()
    {
        return $this->url;
    }
    public function getContent()
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $this->url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
        $html = curl_exec($ch);
        curl_close($ch);
        return $html;
    }
}

2)定义StreamDocument类

<?php
class StreamDocument implements Documentable
{
    protected $resource;
    protected $buffer;
    public function __construct($resource, $buffer = 4096)
    {
        $this->resource = $resource;
        $this->buffer = $buffer;
    }
    public function getId()
    {
        return 'resource-' . (int)$this->resource;
    }
    public function getContent()
    {
        $streamContent = '';
        rewind($this->resource);
        while (feof($this->resource) === false) {
            $streamContent .= fread($this->resource, $this->buffer);
        }
        return $streamContent;
    }
}

3)定义CommandOutputDocument类

<?php
class CommandOutputDocument implements Documentable
{
    protected $command;
    public function __construct($command)
    {
        $this->command = $command;
    }
    public function getId()
    {
        return $this->command;
    }
    public function getContent()
    {
        return shell_exec($this->command);
    }
}

3、定义DocumentStore类

<?php
class DocumentStore
{
    protected $data = [];
    public function addDocument(Documentable $document)
    {
        $key = $document->getId();
        $value = $document->getContent();
        $this->data[$key] = $value;
    }
    public function getDocuments()
    {
        return $this->data;
    }
}

4、使用DocumentStore类

<?php
require 'Documentable.php';
require 'DocumentStore.php';
require 'HtmlDocument.php';
require 'StreamDocument.php';
require 'CommandOutputDocument.php';
$documentStore = new DocumentStore();
// Add HTML document
$htmlDoc = new HtmlDocument('http://php.net');
$documentStore->addDocument($htmlDoc);
// Add stream document
$streamDoc = new StreamDocument(fopen('stream.txt', 'rb'));
$documentStore->addDocument($streamDoc);
// Add terminal command document
$cmdDoc = new CommandOutputDocument('cat /etc/hosts');
$documentStore->addDocument($cmdDoc);
print_r($documentStore->getDocuments());

总结:

使用接口编写的代码更灵活,能委托别人实现细节。使用接口后会有起来越多的人使用你的代码,因为他们只需要知道如何实现接口,就可以无缝地使用你的代码。

源码地址:https://github.com/codeguy/modern-php/tree/master/02-features/interfaces

五、参考

《Modern PHP》Josh Lockhart 著 安道 译

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351

推荐阅读更多精彩内容