簡體   English   中英

為什么PHP中需要抽象類?

[英]Why are abstract classes necessary in PHP?

我們可以使用簡單的繼承或接口而不是抽象。 為什么我們需要在PHP中使用抽象? 我們如何使用抽象隱藏基本功能? 我很困惑使用抽象和接口和繼承。 哪里用哪個? 請幫助理解我。

我認為首先澄清術語是非常重要的,以便更精細地回答這個問題。

  1. 遺產
    • 繼承實際上廣泛應用於許多面向對象的編程原則和概念。 它只需要從另一個繁殖出來的東西。 因此,無論您是實現接口還是擴展類,您仍然使用一種繼承形式。 它們不是相互排斥的概念。
  2. 接口
    • 試着想象一個像合同那樣的界面。 合同本身只是一份文件,通常是兩方或多方之間的文件,規定了他們關系的規則。 接口,特別是在OOP和PHP的上下文中,不提供實現。 它們只提供實現類必須實現的必需公共方法。 接口也無法自行實例化。
  3. 抽象類
    • 抽象類類似於接口,因為它不能單獨實例化,但不一定強制擴展類的合同。 由於它是一個實際的類,而不僅僅是一個接口,它還允許實現。 如果在抽象類中將方法聲明為abstract ,則此實現可以由抽象類本身提供,或者由擴展類提供。 它還允許實現屬性和私有/受保護方法,因為這里的繼承就像一個基類而不僅僅是一個需求。

所以回答這個問題,“ 為什么我們在PHP中有抽象類 ”,因為它很有用。 您可能會首先將這些視為棘手的想法,但它們實際上可以協同工作以提供聯合實用程序。

考慮到有時候接口不足以創建有用的實現。 接口只能強制存在方法,並且其簽名與實現的接口兼容。 例如,可能存在您希望提供接口的默認實現的情況。

interface Device {
    public function input(Stream $in);
    public function output(): Stream;
}

abstract class DefaultDevice implements Device {
    protected $buffer = "";
    public function input(Stream $in) {
        $this->buffer .= $in->read(1024);
        $this->process();
    }
    abstract protected function process();
}

所以現在任何擴展DefaultDevice類都可以選擇覆蓋input方法的實現。 即使接口不需要它,它也必須實現一個process方法。 這意味着實現Device接口的其他類可以向后兼容,這仍然是一個實現細節。

進一步的例子

將實現與規范分開通常是編寫良好的軟件的關鍵屬性。

作為一個很好的例子,看一下Device接口本身。 我們依靠input方法接受Stream類型和output方法來返回Stream類型。 由於Stream本身實際上可以是一個接口,這意味着任何實現Stream類型都是可以接受的。 所以我可以創建自己的類並實現Stream接口,而不會破壞此代碼。

class CustomStream implements Stream {
    public function read($bytes = 1024) {
        /* implementation */
    }
    public function write($data) {
        /* implementation */
    }
}

$device->input(new CustomStream); // this will not throw an error

abstract類用於提供一組數據成員或方法,使其可用於從中繼承的類,即使基類在沒有繼承實現的情況下不是特別有用(並且永遠不應該自己實例化)。

從這里繼承接管。

另一方面, interface是提供一組實現規則,要求每個使用該接口的類實現其中的規范。 實現相同接口的類不需要相互繼承,它們實現接口,因此可以在需要該組功能的任何應用程序中使用它們。

正如練習一樣,我們可以嘗試創建一些類來處理幾何形狀。

基類:

class Shape
{
    public function draw()
    {
    }
}

上面的代碼片段中只描述了基類的相關部分。 當然,它應該具有存儲其位置,線條顏色等的屬性和方法(至少是構造函數)。

一些派生類:

class Circle extends Shape 
{
    public function draw()
    {
        // the code to draw a circle
    }
}

class Rectangle extends Shape
{
    public function draw()
    {
        // the code to draw a rectangle
    }
}

我們可以在基類Shape為方法draw()提供實現嗎?

當然不是。 Shape是通用的,它並不僅僅意味着“圓形”或“矩形”或“三角形”。 沒有辦法為Shape::draw()提供合理的實現,因為我們甚至不知道它代表什么形狀。

是否可以為Shape::draw()提供一個空的實現?

顯然它是。 然而,在第二個想法,很明顯,這是不安全的。 無法draw()擴展Shape並且不為方法draw()提供其自己的實現的類的對象。

因為類Shape無法為方法shape提供合適的實現,所以它應該以某種方式向派生類發出信號,並強制它們提供實現。

它表明這種情況的方式是abstract關鍵字。 abstract方法告訴類的讀者該類無法提供實現,因為它太通用了,它將此責任委托給擴展它的每個類。

具有abstract方法的類未完全定義。 這就是為什么它是一個abstract類而無法實例化的原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM