前言

為了讓自己更能理解各種觀念,因此寫文章來讓自己加深印象,並使用PHP來說明範例。

抽象

簡單來說就是嚴格版的父類別,因為父類別有的功能他幾乎都有,但是有以下四點差異:

  1. 不可實例化
  2. 使用abstract關鍵字定義類別
  3. 可以加入抽象方法,並且子類別必須實作,否則子類別會被標記為抽象類別
  4. 抽象方法可以只定義方法的簽名,也就是方法的名稱與參數,或是也可以定義具體方法

介面

簡單來說就是閹割版抽象類別,並且更加嚴格,因為功能少了很多,使用上多了不少的限制,如以下幾點:

  1. 不可加入具體方法與屬性,方法只能定義簽名,但是可以使用常數
  2. 不可有建構函式
  3. 不可有public以外的定義方式
  4. 子類別不可隨意實作方法,必須全部實作

但是介面也多了一點只有它才有的功能,可支援多重繼承,也就是子類別可同時實現多個介面。
至於兩者的詳細差異請參考以下表格:

兩者差異

差異點 抽象(Abstract) 介面(Interface)
定義 使用 abstract 關鍵字定義 使用 interface 關鍵字定義
實例化 不能直接實例化 不能直接實例化
繼承 類別只能繼承一個 類別可以實現多個
方法實現 可以包含實際實現的方法 只定義方法簽名,無實際實現
建構函式 可以有建構函式 不能有建構函式
子類別 使用 extends 關鍵字繼承 使用 implements 關鍵字實現
方法強制實現 子類別可以選擇性實作方法 子類別必須實作介面定義的方法
適用情境 類別層次結構,共同特性和行為 操作契約,強制相同方法簽名
方法實作限制 可以有訪問修飾詞(public、protected 等) 方法默認是公開的,無其他修飾詞
擴展性 難以支援多重繼承,只能繼承一個類別 支援多重繼承,可以實現多個介面

使用時機

當你想要減少重複的程式碼,又想讓子類別有一定的方法規範,請使用抽象
當你只想要規範子類別方法時,或是同個子類別實作多個不同的介面,請使用介面

範例

抽象

假設你在開發遊戲,遊戲中會有不同的角色,每個角色都會有名字與血量,可選擇不同的職業,但是每個職業都有固定的行為,也就是攻擊與防禦。
因此我可以把角色寫成一個抽象物件,並且規範子類別必須給予角色名字和血量(construct),而且必須有攻擊與防禦的動作(abstract function)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
abstract class Character {
protected $name;
protected $health;

public function __construct($name, $health) {
$this->name = $name;
$this->health = $health;
}

abstract public function attack();
abstract public function defend();

public function displayInfo() {
echo "名字:{$this->name},血量:{$this->health}";
}
}

class Warrior extends Character {
public function attack() {
echo "戰士進行攻擊!";
}

public function defend() {
echo "戰士進行防禦!";
}
}

class Mage extends Character {
public function attack() {
echo "法師施放法術!";
}

public function defend() {
echo "法師進行防護咒語!";
}
}

$characterA = new Warrior('John', '1000');
$characterA->attack(); // 戰士進行攻擊!

介面

舉一個簡單的範例,我想要定義不同的動物是否可以飛或是游泳,而且每個動物的行為都有所差異,因此我定義了兩個介面,只規範行為(function),不寫具體方法,
如此一來各個動物子類別就可以選擇自己需要的介面來實現,並且也可以像是Duck子類別一樣,同時實現兩個介面(多重繼承)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
interface CanFly {
public function fly();
}

interface CanSwim {
public function swim();
}

class Bird implements CanFly {
public function fly() {
echo "鳥可以飛行!";
}
}

class Fish implements CanSwim {
public function swim() {
echo "魚可以游泳!";
}
}

class Duck implements CanFly, CanSwim {
public function fly() {
echo "鴨子可以飛行!";
}

public function swim() {
echo "鴨子可以游泳!";
}
}

補充說明,繼承與實現差異

實現(Implementation):實現通常指的是類別實作某個介面所定義的方法契約。

繼承(Inheritance):繼承是一種類別之間的層次結構,其中子類別可以繼承父類別的屬性和方法。