探索 PHP Abstract Class,物件導向就是不斷的抽象化

Feature image for 探索 PHP Abstract Class,物件導向就是不斷的抽象化

PHP Abstract Class 是物件導向的重要概念,目的是抽象化設計,讓程式更靈活,也是應用設計模式很重要的實作方式。

什麼是 PHP Class

在 PHP 中,Class 是一種用來封裝相關函式和變數的藍圖或模板。當您需要建立多個具有相同特性和行為的物件時,使用 Class 非常有用。

Class 實現了物件導向三要素~

封裝(Encapsulation):

Class 可以將資料(變數)和行為(函式)封裝在一起。

繼承(Inheritance):

一個 Class 可以繼承另一個 Class。

多型(Polymorphism):

透過繼承(Inheritance)和介面(Interface),不同的 Class 可以定義相同的方法。

程式範例

<?php
// 定義一個名為 "Animal" 的 Class
class Animal {
    // 定義一個變數
    public $name;

    // 定義一個函式
    public function makeSound() {
        echo "Some generic animal sound";
    }
}

// 建立一個 Animal 物件
$animal = new Animal();
$animal->name = "Dog";
$animal->makeSound();  // 輸出 "Some generic animal sound"
?>

在這個範例中,我們定義了一個名為 Animal 的 Class,並在其中加入了一個變數 $name 和一個函式 makeSound()。然後,我們建立了一個 Animal 的實例(或物件)並設定其名稱和行為。

這是一個非常精簡的 Class 範例,更多 Class 說明介紹,請參考:PHP 物件導向的基礎,從類別 (Class) 與物件 (Object) 開始

什麼是 PHP Abstract Class

Abstract Class 是一種不能被實例化(不能建立物件)的 Class。它通常包含一個或多個抽象方法,這些方法僅有宣告而無實作。

當您有一些通用的方法,但不希望該 Class 被直接實例化時,應使用 Abstract Class。

程式範例

<?php
// 定義一個名為 "Animal" 的 Abstract Class
abstract class Animal {
    // 定義一個抽象方法
    abstract public function makeSound();

    // 定義一個普通方法
    public function run() {
        echo "Running";
    }
}

// 定義一個繼承自 Animal 的 Class
class Dog extends Animal {
    public function makeSound() {
        echo "Woof";
    }
}

// 建立一個 Dog 物件
$dog = new Dog();
$dog->makeSound();  // 輸出 "Woof"
$dog->run();        // 輸出 "Running"
?>

在這個範例中,我們定義了一個名為 Animal 的 Abstract Class,並在其中定義了一個抽象方法 makeSound() 和一個普通方法 run()。然後,我們建立了一個繼承自 AnimalDog Class,並實作了 makeSound() 方法。

Class 與 Abstract Class 的差異

不同之處

  • Class 可以被實例化,而 Abstract Class 不可以。
  • Abstract Class 可以包含抽象方法,但 Class 不可以。

如何互動合作

通常,Abstract Class 作為基礎 Class,其他 Class 可以繼承它並實現其抽象方法。

程式範例

<?php
// 定義一個名為 "Animal" 的 Abstract Class
abstract class Animal {
    abstract public function makeSound();
}

// 定義一個繼承自 Animal 的 Class
class Dog extends Animal {
    public function makeSound() {
        echo "Woof";
    }
}

// 定義另一個繼承自 Animal 的 Class
class Cat extends Animal {
    public function makeSound() {
        echo "Meow";
    }
}

// 建立物件
$dog = new Dog();
$cat = new Cat();

// 輸出
$dog->makeSound();  // Woof
$cat->makeSound();  // Meow
?>

Simple PHP Abstract Class Diagram

Class Diagram

為什麼這樣設計?

抽象基類別(Abstract Base Class)Animal 作為一個抽象基類別,定義了所有動物都應該有的基本行為,例如 makeSound()

具體子類別(Concrete Subclasses)DogCatAnimal 的具體子類別,它們繼承了 Animal 的特性並提供了 makeSound() 方法的具體實作。

方法覆寫(Method Overriding):在 DogCat 類別中,我們覆寫了 makeSound() 方法,以提供各自特有的行為。

好處是什麼?

程式碼重用(Code Reusability):透過使用繼承,DogCat 類別可以重用 Animal 類別中的程式碼。這減少了重複程式碼,使得程式碼更為簡潔。

可維護性(Maintainability):如果未來需要更改動物的共同行為,只需要在 Animal 類別中進行更改,而不需要在每一個子類別中單獨修改。

可擴展性(Extensibility):如果未來需要新增更多種動物,只需要繼承 Animal 類別並提供新的 makeSound() 實作。這樣可以輕鬆地擴展程式。

多型(Polymorphism):由於 DogCat 都是 Animal 類型,我們可以使用多型來處理各種不同的動物,而不需要知道它們的具體類型。

高度抽象(High Abstraction):使用 Abstract Class,我們可以定義一個高度抽象的框架,這有助於理解各個類別之間的關係,並強制子類別實作某些方法。

進階 Abstract Class 範例

<?php
// 定義一個名為 "Vehicle" 的 Abstract Class
abstract class Vehicle {
    public $speed;

    // 定義一個抽象方法
    abstract public function move();

    // 定義一個普通方法
    public function setSpeed($speed) {
        $this->speed = $speed;
    }
}

// 定義一個繼承自 Vehicle 的 Abstract Class
abstract class LandVehicle extends Vehicle {
    public $wheels;

    // 覆寫 move 方法
    public function move() {
        echo "Moving on land at speed " . $this->speed;
    }

    // 定義一個新的抽象方法
    abstract public function honk();
}

// 定義一個繼承自 LandVehicle 的 Class
class Car extends LandVehicle {
    public $brand;

    // 實現 honk 方法
    public function honk() {
        echo "Honking";
    }
}

// 建立一個 Car 物件
$car = new Car();
$car->setSpeed(100);  // 設定速度
$car->move();         // 輸出 "Moving on land at speed 100"
$car->honk();         // 輸出 "Honking"
?>

在這個範例中,我們首先定義了一個名為 Vehicle 的 Abstract Class,其中包含一個抽象方法 move() 和一個普通方法 setSpeed()

然後,我們定義了一個繼承自 Vehicle 的 Abstract Class LandVehicle。在這個 Class 中,我們覆寫了 move() 方法並新增了一個新的抽象方法 honk()

最後,我們定義了一個繼承自 LandVehicle 的 Class Car,並實作了 honk() 方法。

這個範例展示了如何在多層繼承中使用 Abstract Class,以及如何覆寫和實作抽象方法。

PHP Abstract Class Diagram

Class Diagram

為什麼這樣設計?

多層繼承(Multi-level Inheritance):在這個範例中,我們有一個 Vehicle Abstract Class,以及一個繼承自 VehicleLandVehicle Abstract Class。這種多層繼承允許我們更細緻地組織程式碼。

方法覆寫(Method Overriding)LandVehicle Class 覆寫了 Vehicle Class 中的 move() 方法。這樣做是為了提供更具體的實作。

抽象與具體方法(Abstract and Concrete Methods)VehicleLandVehicle 都有抽象方法(需要子類別實作的方法),但也有具體方法(已經實作的方法)。這提供了一個平衡,使得 Class 既靈活又具有一定的結構。

有什麼好處?

程式碼重用(Code Reusability):透過繼承,我們可以重用 VehicleLandVehicle 中的程式碼,這減少了重複程式碼。

可維護性(Maintainability):使用 Abstract Class 和多層繼承使得程式碼更容易維護。如果需要更改移動的方式,我們只需要在一個地方(如 VehicleLandVehicle)進行更改。

可擴展性(Extensibility):如果未來需要新增更多種交通工具(如 AirVehicleWaterVehicle 等),這種設計使得擴展變得非常容易。

結構清晰(Clear Structure):這種多層繼承和方法覆寫的結構使得程式碼更加組織化,更容易理解。

高度抽象(High Abstraction):透過使用 Abstract Class,我們定義了一個高度抽象的框架,這有助於理解各個 Class 之間的關係。

實作細節隱藏(Implementation Hiding):Abstract Class 提供了一個介面,但隱藏了實作的細節。這有助於封裝和資訊隱藏。

參考文章: