在物件導向程式設計中,物件的建立過程往往伴隨著複雜的邏輯判斷。當系統中存在大量相似介面的類別,且需要根據不同條件動態實例化時,直接使用 new 關鍵字會導致程式碼耦合度過高、難以維護。工廠模式正是為了解決這一問題而生——它將物件的建立邏輯封裝在專門的「工廠」類別中,實現「建立者」與「使用者」的解耦。
根據經典定義,工廠模式包含三個不可或缺的角色:
簡單工廠模式又稱靜態工廠方法模式,透過一個工廠類別的靜態方法來建立產品。雖然不屬於 GoF 23 種經典設計模式之一,但在實務開發中極為常見。
<?php
// 產品抽象模型
abstract class Model {
abstract public function getName();
}
// 具體產品:張三
class ZhangSan extends Model {
public function getName() {
return "我的名字是張三";
}
}
// 具體產品:李四
class LiSi extends Model {
public function getName() {
return "我的名字是李四";
}
}
// 工廠類別
class NameFactory {
public static function create($type) {
switch ($type) {
case 'zhangsan':
return new ZhangSan();
case 'lisi':
return new LiSi();
default:
throw new InvalidArgumentException("未知的類型: $type");
}
}
}
// 客戶端使用
$person = NameFactory::create('zhangsan');
echo $person->getName(); // 輸出:我的名字是張三
?>
優點:邏輯集中、呼叫簡單。
缺點:新增產品時需修改工廠類別,違反「開閉原則」。
工廠方法模式將建立物件的具體邏輯下放到子類別中,工廠介面只定義建立方法的簽名,由具體工廠決定實例化哪個產品。這樣新增產品時只需新增對應的工廠類別,無需修改既有程式碼。
<?php
// 產品介面
interface Link {
public function getUrl();
}
// 具體產品
class WebLink implements Link {
public function getUrl() {
return "https://www.jb51.net";
}
}
// 抽象工廠
interface LinkFactory {
public function createLink(): Link;
}
// 具體工廠
class WebLinkFactory implements LinkFactory {
public function createLink(): Link {
return new WebLink();
}
}
// 使用
$factory = new WebLinkFactory();
$link = $factory->createLink();
echo $link->getUrl(); // 輸出:https://www.jb51.net
?>
當系統需要建立一組相關或相依的物件,而不需指定它們的具體類別時,抽象工廠模式最為適合。例如:同一廠牌的滑鼠、鍵盤、螢幕必須搭配使用。
<?php
// 產品族介面
interface Mouse { public function click(); }
interface Keyboard { public function type(); }
// 具體產品族 A (Logitech)
class LogitechMouse implements Mouse { public function click() { echo "羅技滑鼠點擊\n"; } }
class LogitechKeyboard implements Keyboard { public function type() { echo "羅技鍵盤輸入\n"; } }
// 具體產品族 B (Razer)
class RazerMouse implements Mouse { public function click() { echo "雷蛇滑鼠點擊\n"; } }
class RazerKeyboard implements Keyboard { public function type() { echo "雷蛇鍵盤輸入\n"; } }
// 抽象工廠
interface ComputerFactory {
public function createMouse(): Mouse;
public function createKeyboard(): Keyboard;
}
// 具體工廠
class LogitechFactory implements ComputerFactory {
public function createMouse(): Mouse { return new LogitechMouse(); }
public function createKeyboard(): Keyboard { return new LogitechKeyboard(); }
}
class RazerFactory implements ComputerFactory {
public function createMouse(): Mouse { return new RazerMouse(); }
public function createKeyboard(): Keyboard { return new RazerKeyboard(); }
}
// 客戶端
function setupWorkstation(ComputerFactory $factory) {
$mouse = $factory->createMouse();
$keyboard = $factory->createKeyboard();
$mouse->click();
$keyboard->type();
}
setupWorkstation(new LogitechFactory());
// 輸出:
// 羅技滑鼠點擊
// 羅技鍵盤輸入
?>
new 即可,無需引入工廠。工廠模式是物件導向設計中最基礎也最實用的模式之一。掌握其三種變體——簡單工廠、工廠方法、抽象工廠——並理解各自的適用場景,能幫助你撰寫出低耦合、高擴充性、易測試的 PHP 程式碼。記住:模式是為了解決問題而存在的,不是為了用模式而用模式。