簡體   English   中英

PHP - 如果抽象類中的所有方法都是抽象的,那么接口和抽象類之間的區別是什么

[英]PHP - if all methods in abstract class are abstract then what is the difference between interface and abstract class

抽象類可能有也可能沒有抽象方法,但接口只有未實現的方法。 那么,如果我的抽象類將其所有方法標記為抽象,那么使用接口的區別和優勢是什么?

接口和抽象
真正的使用能力可以在龐大的API中體現出來,其中包含大量的類,這些類遵循經過深思熟慮的靈活結構,以便將來編碼。 是否可能發生 - 您永遠不知道代碼是否會被擴展。 接口僅用於語義原因。 想象一下,您擴展了一個已棄用的API版本,並且可以編輯/更改/實現/更新/改進/擴展/修改代碼以使其更新,無論原因是什么。 如果你沒有想到,你最終會感到沮喪。

可以在沒有接口的情況下制作小型API,這也是大多數人認為接口不必要的地方。 但是一旦它們變大,它們就會失去靈活性。 他們為您提供課程合同,提醒您需要什么並保持概述。 接口必須有公共方法,如果你有保護或私有方法,只需在實現接口的類的公共方法中返回它們。

就像你已經解釋過的那樣,接口需要實現特定的方法,抽象類不要求它,因為你最有可能擴展它們。 可以重新定義方法,並且必須在子類中定義抽象方法。 接口中提到的方法僅告訴您與接口簽訂合同的類必須具有這些定義的類。 它可以是多個接口,您不會像使用抽象類那樣繼承它們。

這樣想
其中的邏輯是預測您計划構建的未來。 無論是建築,基礎設施還是工廠的大規模生產。 就像您對書簽,書籍,文件夾中的圖像等項目進行排序一樣。 因為您知道如果您沒有對其進行排序,則需要更長時間才能找到特定圖像。 抽象和接口的語義目的是類似的,尤其是在大型API中。

  • 界面重現了可能性和要求的框架。
  • 抽象保留了在派生上下文中相關的概念信息。

我將向您展示一個具有簡化內容的API啟動的典型結構,其中接口和抽象類具有未來擴展的真實使用點。

/* Considering, this project will be widely expanded up to huge complexity. 
   This is a flexible base structure, for developers working in team. Imagine 
   there could be lots more variation of styles for certain purposes. */


// OOP STRUCT
// You might want to define multiple interfaces to separate the project
interface iString {
    // These methods MUST be defined or else the developer receives an error
    public function getContent();
    public function description($desc);
}

/* Devs might want to add an additional method later on. 
   Traits are useful for quick use. (optional) */

trait desc {

    private $desc;

    public function description($desc) {
        return $this->desc;
    }
}


/* This is the base class for the content which requires a declaration 
   of methods being described in the interface */

class contents implements iString {

    use desc; // use the method defined in a trait
    private $str;

    public function __construct($str) {
        $this->str = $str;
    }

    public function getContent() {
        return $this->str;
    }
}


/* Or devs often consider abstract classes as the real base of the whole project/app.
   Abstract classes allow the use of methods that can be modified/declared for further use in derived classes.
   Interfaces can't do that */

abstract class stylize {

    private $str;

    // This typehint below makes sure that this value is assigned on interface
    public function __construct(iString $str) { 
        $this->str = $str;
    }

    public function style() {
        return $this->str->getContent();
    }

    abstract public function getContent();
}


// EXTENDED CLASSES 
class bold extends stylize {
    // Extended classes have to define abstract methods inherited from an abstract class. Non-abstract methods are not needed.
    public function getContent() {
        return "<strong>".parent::style()."</strong>";
    }
}

class underline extends stylize {

    public function getContent() {
        return "<u>".parent::style()."</u>";
    }
}

class upperCase extends stylize {

    public function getContent() {
        return strtoupper(parent::style());
    }
}


// PROCEDUAL OUTPUT

// A tiny shortcut
$e = function($desc,$str) { echo $desc.": ".$str->getContent()."<br>"; };

// Content being used
$content = new contents('Hello World.');
$e("Normal",$content);

// Content being styled
$bold = new bold($content);
$underline = new underline($content);
$upper = new upperCase($content);

// Renders content with styles        
$e("Bold",$bold);
$e("Underline",$underline);
$e("Uppercase",$upper);

結論
應用文本內容的樣式作為示例可能不夠吸引人。 但除此之外,它仍然是相同的 - 如果它做它應該做的事情,那么就完成了。 就像我將構建可擴展的eMail配置API作為CMS的模塊一樣。 該結構在正確編碼中具有語義過程。

的竅門
我建議你繼續學習這種模式的小項目,即使你認為接口不值得。 繼續這樣做,直到你把它放進去。 我個人對你的建議:如果你認為你不知道從哪里開始以及嘗試什么項目,那么試試現實世界的例子就是遵循這個邏輯:

Vehicles (abstract class)
-> Ferrari (extended class)
-> Truck (extended class)

both have wheels (property)
both must be able to drive (method)

they perform a 1mile match race on a street (abstract method)

one is a slowpoke (extended property)
one is red one is blue (extended property)

and later a 3rd one comes and its a train (extended class)

who's going to win (some method)

Instantiate all vehicles and maintain privileges over interface and 
abstraction.
...something like this...

通常,包含巨大主體的類應該在單個文件中分開+包括這些+定義命名空間。 否則代碼牆會讓你或其他人感到厭倦。 使用Eclipse ,最好的應用程序來維護OOP。

此外,如果它適合您的項目,如果您有Linux Ubuntu ,請使用phUML 如果您有很多相關類,它會為您當前的構建生成一個圖形圖表。

在此輸入圖像描述

phUML是基於UML的PHP​​ API。 它是一個開源項目,可以為幾乎任何流行的編程語言生成任何可視化方案。 我經常使用它,而不僅僅是PHP。 只需在Github上克隆它,或從dasunhegoda.com下載並按照安裝指南進行操作。
您也會對此感興趣: 在接口上進行類型設置

抽象類允許“部分實現”(參見模板方法模式),但在這種情況下,如果所有方法都是抽象的,那么您看不到這種好處。 您可以做的另一件事是包括字段,您不僅限於方法。

請記住,“抽象方法”與接口定義的契約之間存在概念上的區別。 抽象方法必須由子類覆蓋,該子類通過繼承實現來完成。 任何多態調用(向下轉換)都需要每個類一個超類,否則會遇到鑽石繼承問題。 這種基於繼承的樹結構是OO設計的典型。

相比之下,界面提供了履行契約的簽名。 只要保留簽名,就可以滿足許多接口的需求,因為不存在返回類層次結構以查找其他實現的問題。 接口實際上並不依賴於多態來實現這一點,而是基於契約。

另外需要注意的是,你可能有“受保護”的抽象方法,在接口中做這樣的事情是沒有意義的(實際上這樣做是違法的)。

如果abstract class將其所有方法定義為abstract則必須在任何子類中定義其主體,並且它顯示與interface類似的行為。

好處:

使用interface而不是abstract類,您可以在使用abstract類時implement多個interfaces ,一次只能擴展one類。

編輯

我發現的另一個區別是abstract類可以有constructorinterface不能有。

REF: php中抽象類中構造函數的用法是什么

暫無
暫無

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

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