在 Laravel (以及一般的 PHP 物件導向程式設計) 中,interface
(介面) 和 class
(類別) 是兩個核心概念,它們有著根本性的區別和各自的用途:
Class (類別)
- 實體化 (Instantiation):
Class
是用來建立物件 (Object) 的藍圖。你可以直接new
一個Class
來創建它的實例。 - 具體實現 (Concrete Implementation):
Class
可以包含屬性 (properties) 和方法 (methods) 的具體實現邏輯。也就是說,方法內部有實際的程式碼來執行某些操作。 - 單一繼承 (Single Inheritance): 在 PHP 中,一個
Class
只能繼承 (extend) 一個父類別。這意味著一個類別只能從一個父類別獲得其屬性和方法。 - 用途: 用於定義物件的行為和狀態,並提供這些行為的實際執行方式。例如,
User
類別可能包含name
和email
屬性,以及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 中,interface
和 class
的區別尤其重要,因為 Laravel 廣泛使用了依賴注入 (Dependency Injection) 和服務容器 (Service Container)。
- **依賴注入:**當你將一個
interface
作為型別提示 (type-hint) 注入到建構子或方法中時,Laravel 的服務容器會自動尋找一個實作了該interface
的「具體類別」(concrete class) 並將其注入。- 好處:這使得你的程式碼更加彈性和可測試。你可以輕鬆地切換不同的實現(例如,從 Stripe 支付切換到 PayPal 支付),而不需要修改依賴於
PaymentGatewayInterface
的程式碼。在測試時,你可以注入一個「模擬物件」(mock object) 來模擬interface
的行為,而不需要依賴真實的外部服務。
- 好處:這使得你的程式碼更加彈性和可測試。你可以輕鬆地切換不同的實現(例如,從 Stripe 支付切換到 PayPal 支付),而不需要修改依賴於
- **服務提供者 (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
則用於定義這些功能的抽象契約,這使得你的應用程式更加健壯、可擴展和易於維護。
沒有留言:
張貼留言