關於抽象類和介面的初步理解

線上猛如虎發表於2019-02-16

關於抽象類和介面的初步理解

什麼是抽象類

  1. 抽象類是指在 class 前加了 abstract 關鍵字且存在抽象方法(在類方法 function 關鍵字前加了 abstract 關鍵字)的類。

  2. 抽象類不能被直接例項化。抽象類中只定義(或部分實現)子類需要的方法。子類可以通過繼承抽象類並通過實現抽象類中的所有抽象方法,使抽象類具體化。

  3. 如果子類需要例項化,前提是它實現了抽象類中的所有抽象方法。如果子類沒有全部實現抽象類中的所有抽象方法,那麼該子類也是一個抽象類,必須在 class 前面加上 abstract 關鍵字,並且不能被例項化。
    引用連結

  1. 介面(Interface)—— 定義行為

  2. 抽象類(Abstract Class) —— 實現行為

  3. 具體類(class)——執行行為
    引用連結

  1. 抽象類就是一個類的服務提供商,擁有眾多服務,你不用必須用,當需要的時候你來用就可以,如果你覺得不提供服務不滿意,你還可以自己來做。

  2. 抽象方法是必須實現的方法。就象動物都要呼吸。但是魚用鰓呼吸,豬用肺呼吸。
    動物類要有呼吸方法。怎麼呼吸就是子類的事了。

引用連結

為什麼要使用抽象類

按照我目前的知識理解:

  1. 保持程式的一致性

  2. 抽象類限制了實現的方法,也是為了保持一致性

  3. 增加程式碼重用性,例如一些公共類不需要實現,只需要呼叫裡面的方法就可以了。

  4. 現在有很多討論和建議提倡用interface代替abstract類,兩者從理論上可以做一般性的混用,但是在實際應用中,他們還是有一定區別的。抽象類一般作為公共的父類為子類的擴充套件提供基礎,這裡的擴充套件包括了屬性上和行為上的。而介面一般來說不考慮屬性,只考慮方法,使得子類可以自由的填補或者擴充套件介面所定義的方法,就像JAVA王子所說的事件中的介面卡就是一個很好的應用。

用一個簡單的例子,比如說一個教師,我們把它作為一個抽象類,有自己的屬性,比如說年齡,教育程度,教師編號等等,而教師也是分很多種類的,我們就可以繼承教師類而擴充套件特有的種類屬性,而普遍屬性已經直接繼承了下來。

而介面呢~還是拿教師做例子,教師的行為很多,除了和普通人相同的以外,還有職業相關的行為,比如改考卷,講課等等,我們把這些行為定義成無body的方 法,作為一個集合,它是一個interface。而教師張三李四的各自行為特點又有不同,那麼他們就可以擴充套件自己的行為body。從這點意義上來說,interface偏重於行為。

引用連結

怎樣使用抽象類

<?php
    abstract class  Shape{  //這是一個抽象類,不能例項化
        protected  $color;  //抽象類裡面一般都是使用protected來保護屬性,這是封裝的意義
        
        public function __construct($color = `red`) {   //抽象類可以使用構造方法,主要是為了方便程式碼重用,構造方法裡面也可以使用預設引數,當沒有配置引數的時候,就會使用預設的引數,寫法如上
            $this->color = $color;
        }
        
        public function getColor() {  //只是為了演示需要的一個方法
            return $this->color;
        }
        
        abstract public function getArea();  //構造方法是為了限制程式碼,對於繼承這個構造類的子類,必須限制擁有這個構造方法,主要為了保持程式碼一致性。
    }
    
    class Square extends Shape{
        protected  $length = 4;
        public function getArea() {
            return pow($this->$length, 2);
        }
    }
    
    class Circle extends Shape{ //這裡因為沒有構造方法getArea,所以程式碼允許會報錯的。
        
    }
    
    $shape = new Square();
    var_dump($shape);
?>

介面和抽象類

  1. 抽象類不能被直接例項化,抽象類中只定義子類需要的方法,子類可以繼承並且通過實現其中的抽象方法,使抽象類具體化。例如一個名為media的類,他是用於描述各種公開出版的共同性質,因為media不表示真實的實體,而是一些相似實體的泛化表示,所以不例項化,這樣就需要宣告為抽象類,然後再由各種的派生的Media類繼承此抽象類

  2. 抽象類的每個子類都必須實現抽象類中的所有抽象方法,或者把他們自身也宣告為抽象方法。

  3. 擴充套件類不僅僅負責簡單實現抽象類的方法,還必須重新宣告方法,新的方法不能比抽象方法的訪問控制更嚴格,新的實現方法的引數個數應該和抽象方法的引數個數一樣。

  4. 介面定義了實現某種服務的一般規範,宣告瞭必須的函式和常量,但是不指定如何實現。關鍵是要建立必須實現的一組一般原則,只有滿足了這些原則才能說實現了這個介面。

  5. 抽象類提供了具體實現的標準,而介面則是純粹的模板。介面只能定義功能而不包含實現的內容。

  6. 任何實現介面的類都要實現介面中所定義的所有方法,否則類必須宣告為abstract。

  7. 實現介面的類接受他的繼承的類以及實現的介面的型別。

什麼時候用介面,什麼時候用抽象類

  • 如果要建立一個模型,這個模型將由一些緊密相關的物件引用,就可以採用抽象類,如果要建立將由一些不想關的物件採用的功能,應該用介面。

  • 如果必須從多個來源繼承行為,就是用介面。

  • 如果知道所有類都會共享一個公共的行為實現,就使用抽象類,並在其中實現行為。介面無法實現。

  • 一個類只能extends一個父類,但可以貫徹多個介面。

介面作用一:

介面類就是一個類的領導者,指明方向,子類必須完成它指定方法。

當有很多人一起開發一個專案時,可能都會去呼叫別人寫的一些類,那你就會問,我怎麼知道他的某個功能的實現方法是怎麼命名的呢,這個時候php介面類就起到作用了,當我們定義了一個介面類時,它裡面的方式是下面的子類必須實現的,比如

interface Shop
{
public function buy($gid);
public function sell($gid);
public function view($gid);
}

class BaseShop implements Shop
{
    public function buy($gid)
    {
        echo `你購買了ID為 :` . $gid . `的商品`;
    }

    public function sell($gid)
    {
        echo `你購賣ID為 :` . $gid . `的商品`;
    }

    public function view($gid)
    {
        echo `你瀏覽了ID為 :` . $gid . `的商品`;
    }
}

介面作用二:

有時候,我們需要設計一個物品,比如shape,這個shape有不同的形狀,有不同的顏色,可作不同的運動,等等。當然我們可以把這些都放在一個類裡面,但這樣,如前面說的,只是過程程式設計,不是OO程式設計。你會說,像上面例子一樣,做一個抽象類,然後在子類裡實現所有的功能。好象不錯,進步了。這樣子類裡面要實現形狀,顏色,運動等功能,OK嗎?記住,OO裡面還有一條原則,為了最大程度的做到程式碼重用,一個類裡最好只實現一個功能,也就是說,一個類做形狀,一個類做顏色,一個類做運動 。這樣如果其他的類要用到顏色的功能時,我們就可以重用這個顏色類,同理,這樣我們可以很容易的重用運動類,形狀類,等等。

但這樣問題出來了,現在我們要用到上面所有的功能,但又分散在三個類裡面,怎麼辦?這時我們就要用到抽象類和介面了。選定一個跟shape關聯最大的一項–形狀,把它做成抽象類, 其他兩樣,把它們做成介面,然後在子類裡面extends一個抽象類,再implements兩個介面就行了。如:

class Square extends Shape implements 顏色, 運動, ... {
...
}

抽象類作用一:

抽象類就是一個類的服務提供商,擁有眾多服務,你不用必須用,當需要的時候你來用就可以,如果你覺得不提供服務不滿意,你還可以自己來做。

這裡是一個例子,想上面一樣我定義了一個商店類,抽所了它所有像的部分,買(buy),賣(sell),看(view),並且抽象類裡都實現了這些方法,那麼繼承它的子類就自動獲得了這些方法,子類就做它自己獨特的東西,減少程式碼的重複,提高複用性。

abstract class BaseShop
{
    public function buy($gid)
    {
        echo `你購買了ID為 :` . $gid . `的商品`;
    }

    public function sell($gid)
    {
        echo `你購賣ID為 :` . $gid . `的商品`;
    }

    public function view($gid)
    {
        echo `你瀏覽了ID為 :` . $gid . `的商品`;
    }
}

class BallShop extends BaseShop
{
    var $itme_id = null;

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

    public function open()
    {
        $this->sell($this->itme_id);
    }
}

抽象類作用二:

在抽象類裡面設定抽象方法

在oo設計時,會把一些通用的方法放在一個類裡,但考慮到子類繼承時的差異性,又不能把它事先實現,就只好用到這個抽象類或介面了。這裡很清楚的顯示了在抽象類裡,我們貫徹了設原用到點setCenter()的方法,這樣,當子類繼承它時,就不用再重複寫這個設原點的方法了。那麼為什麼draw的方法要設定成抽象方法呢?這是因為不同的子類要用不同的實現方法。

abstract class Shape
{
    function setCenter($x, $y)
    {
        $this->x = $x;
        $this->y = $y;
    }

    abstract function draw();

    protected $x, $y;
}

參考:http://chengxudaren.com/index.php?act=article&op=detail&a_id=152

相關文章