抽象類別(Abstract Class)與介面(Interface)

甚麼是抽象?

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

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

案例示範 :

下面寫的抽象類我們強制之後的類都必須完成calcPrice & calcSalary方法。

abstract class Shop
{
    public $count = 0;

    abstract protected function calcPrice($Price);
    abstract protected function calcSalary($Hours);
}

寫兩個類別繼承抽象類別Shop,並在裡面完成在抽象類別定義過的方法。

class Starbucks extends Shop
{
    public function calcPrice($Price)
    {
        return $Price * 5;
    }

    public function calcSalary($Hours)
    {
        return $Hours * 200;
    }
}

class SevenEleven extends Shop
{
    public function calcPrice($Price)
    {
        return $Price * 2;
    }

    public function calcSalary($Hours)
    {
        return $Hours * 100;
    }
}

實體化 Starbucks 跟 SevenEleven後輸出。

$expCoffeeShop = new Starbucks;
$budgetCoffeeShop = new SevenEleven;

echo $expCoffeeShop->calcPrice(100)."\n";
echo $expCoffeeShop->calcSalary(200)."\n";

echo $budgetCoffeeShop->calcPrice(100)."\n";
echo $budgetCoffeeShop->calcSalary(200)."\n";

output :

500
40000
200
20000

為甚麼我們需要使用抽象類別?

抽象類別允許使用者建立一個可以被實作或覆寫的子類別,當有人想請程式設計師寫類別方法但又只知道方法名字而不知道方法細節程式設計師要怎麼寫,這個時候就可以使用抽象類別。

甚麼是interface?

interface是class的模板,定義實現它的class需要實現哪些methods。

interface將會強迫用戶去實現一些method。例如有一個class中必須要求set ID和Name這兩個屬性,那麼我們就可以把這個class申明為interface,這樣所有實作自這個class的子類別都將強制必須實現setId和setName兩個操作。

案例示範:

定義必填的兩個屬性。

interface template
{
    public function setId($a)
    public function setName($name)
}

在繼承的class裡完成強制需要被寫入的方法。

class Studenta implements template
{
    public function setId($a)
    {
        return 'id:'.$a;
    }
    public function setName($name)
    {
        return 'Name:'.$name;
    }
}

$firstStudent = new Studenta;

echo $firstStudent->setId(1)."\n";
echo $firstStudent->setName('Steve');

output:

id:1
Name:Steve

Abstract class VS Interface

相同點:
  1. 兩者都無法直接實體化。
  2. 都可以寫抽象方法(可以讓抽象類或介面內的方法空著)。
  3. 都可以擁有常數(const)成員。
相異點:
  • 介面無法宣告屬性。
  • 介面無法實作方法。
interface template
{
    public function setId($a);
    public function setName($name);
    function test() {
        echo '123';        //需要保持function內是空的
    }
}

報錯:

Fatal error: Interface function template::test() cannot contain body in /Users/sc/Desktop/php-practice/interface.php on line 7
  • 一個class可以同時implements好多個介面,但是在抽象類別中,子類別只可以實作一個抽象類別。
  • interface中的method必須是public的,但是在abstract class中可以是public或者protected。

為什麼我們需要使用Interface?

當多個類別之間有共同的 function,但 function 實做的方式有差異,可以將這些共用 function 寫成Interface,讓其他的子類別去實做這個介面。因為這樣對其他程式碼所展示的共同區域是相同的,所以可以提高程式整體的工作效率。