2025年6月10日 星期二

Laravel 中 interface (介面) 和 class (類別) 的差別為何?

 在 Laravel (以及一般的 PHP 物件導向程式設計) 中,interface (介面) 和 class (類別) 是兩個核心概念,它們有著根本性的區別和各自的用途:

Class (類別)

  • 實體化 (Instantiation): Class 是用來建立物件 (Object) 的藍圖。你可以直接 new 一個 Class 來創建它的實例。
  • 具體實現 (Concrete Implementation): Class 可以包含屬性 (properties) 和方法 (methods) 的具體實現邏輯。也就是說,方法內部有實際的程式碼來執行某些操作。
  • 單一繼承 (Single Inheritance): 在 PHP 中,一個 Class 只能繼承 (extend) 一個父類別。這意味著一個類別只能從一個父類別獲得其屬性和方法。
  • 用途: 用於定義物件的行為和狀態,並提供這些行為的實際執行方式。例如,User 類別可能包含 nameemail 屬性,以及 save()login() 方法。
PHP
<?php

class User
{
    public $name;
    public $email;

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

    public function save()
    {
        // 儲存使用者資料到資料庫的邏輯
        echo "Saving user {$this->name} to database.\n";
    }
}

$user = new User('John Doe', 'john@example.com');
$user->save(); // Output: Saving user John Doe to database.

Interface (介面)

  • 契約 (Contract): Interface 是一個「契約」或「規範」。它定義了一組方法簽名 (method signatures),但不提供任何方法實現的細節。
  • 不可實體化 (Cannot be Instantiated): 你不能直接 new 一個 Interface。它只是一個骨架,必須由 Class 來「實作」(implement)。
  • 強制實現 (Enforced Implementation): 任何 Class 如果聲明實作了某個 Interface,就必須提供該 Interface 中所有方法的具體實現。如果沒有,PHP 會拋出一個致命錯誤。
  • 多重實作 (Multiple Implementation): 一個 Class 可以實作多個 Interface。這彌補了 PHP 單一繼承的限制,允許類別具有多種不同的行為契約。
  • 目的: 主要是用於定義通用的行為規範,促進程式碼的模組化、彈性和可測試性。它強調「是什麼」(what) 而不是「如何做」(how)。
PHP
<?php

interface PaymentGatewayInterface
{
    public function pay(float $amount): bool;
    public function refund(string $transactionId, float $amount): bool;
}

class StripePaymentGateway implements PaymentGatewayInterface
{
    public function pay(float $amount): bool
    {
        // 實際使用 Stripe 支付的邏輯
        echo "Processing payment of {$amount} via Stripe.\n";
        return true;
    }

    public function refund(string $transactionId, float $amount): bool
    {
        // 實際使用 Stripe 退款的邏輯
        echo "Refunding {$amount} for transaction {$transactionId} via Stripe.\n";
        return true;
    }
}

class PayPalPaymentGateway implements PaymentGatewayInterface
{
    public function pay(float $amount): bool
    {
        // 實際使用 PayPal 支付的邏輯
        echo "Processing payment of {$amount} via PayPal.\n";
        return true;
    }

    public function refund(string $transactionId, float $amount): bool
    {
        // 實際使用 PayPal 退款的邏輯
        echo "Refunding {$amount} for transaction {$transactionId} via PayPal.\n";
        return true;
    }
}

// 在 Laravel 中,通常會搭配依賴注入 (Dependency Injection) 和服務容器 (Service Container) 使用
// 例如,在控制器中可以這樣接收 PaymentGatewayInterface
class PaymentController
{
    public function process(PaymentGatewayInterface $gateway, float $amount)
    {
        if ($gateway->pay($amount)) {
            echo "Payment successful!\n";
        } else {
            echo "Payment failed!\n";
        }
    }
}

// 在 Laravel 的 ServiceProvider 中綁定實現
// App::bind(PaymentGatewayInterface::class, StripePaymentGateway::class);

// 然後在控制器中使用
// $controller = app(PaymentController::class); // Laravel 會自動注入 StripePaymentGateway
// $controller->process(100.00);

Laravel 中的應用與差異

在 Laravel 中,interfaceclass 的區別尤其重要,因為 Laravel 廣泛使用了依賴注入 (Dependency Injection)服務容器 (Service Container)

  • **依賴注入:**當你將一個 interface 作為型別提示 (type-hint) 注入到建構子或方法中時,Laravel 的服務容器會自動尋找一個實作了該 interface 的「具體類別」(concrete class) 並將其注入。
    • 好處:這使得你的程式碼更加彈性可測試。你可以輕鬆地切換不同的實現(例如,從 Stripe 支付切換到 PayPal 支付),而不需要修改依賴於 PaymentGatewayInterface 的程式碼。在測試時,你可以注入一個「模擬物件」(mock object) 來模擬 interface 的行為,而不需要依賴真實的外部服務。
  • **服務提供者 (Service Providers):**在 Laravel 的 Service Providers 中,你通常會定義 interface 和其對應的 class 綁定關係。這樣,當 Laravel 需要 interface 的實例時,它就知道要提供哪個 class 的實例。

總結來說:

特性Class (類別)Interface (介面)
定義具體實現,包含屬性和方法的實際邏輯。契約或規範,只定義方法簽名,不含任何實現邏輯。
實體化可以直接 new 實體化為物件。不能直接 new,必須由 Class 實作後才能使用。
繼承/實作只能 extend 一個父類別。可以 implement 多個介面。
用途建立物件,提供具體的功能。定義行為規範,實現多型,提高程式碼的靈活性和可測性。
程式碼內容包含實際的邏輯和程式碼。只有方法簽名 (名稱、參數、回傳型別),沒有方法體。
強調點「如何做」 (How to do it)「是什麼」 (What it does)

在 Laravel 開發中,你會經常使用兩者。Class 用於實現具體功能,而 Interface 則用於定義這些功能的抽象契約,這使得你的應用程式更加健壯、可擴展和易於維護。

沒有留言:

張貼留言

網誌存檔