直接 new User('小明', 19) 看似簡單,但當類構造函數參數變更(如新增 $group 字段)時,所有調用處都需修改。若該類在項目中被實例化數十上百次,維護成本極高。工廠模式將「如何創建對象」封裝隔離,實現 創建邏輯與業務邏輯解耦。
interface IUser {
public function getName();
public function getAge();
}
class User implements IUser {
protected $_name;
protected $_age;
public function __construct(string $name, int $age) {
$this->_name = $name;
$this->_age = $age;
}
public function getName(): string { return $this->_name; }
public function getAge(): int { return $this->_age; }
}
// 調用處
$u = new User('小明', 19); // 當需新增 $group 時,所有 new 處必須改
public function __construct(string $name, int $age, string $group = '默認組') { ... }
// 雖不報錯,但隱性依賴默認值,業務語義模糊,違反「顯式優於隱式」
class UserFactory {
/** 參數配置集中管理,可遷移至配置文件/數據庫 */
private static $presets = [
0 => ['name' => '小明', 'age' => 19, 'group' => '學生'],
1 => ['name' => '小王', 'age' => 19, 'group' => '學生'],
// 更多預設...
];
public static function create(int $id): IUser {
if (!isset(self::$presets[$id])) {
throw new InvalidArgumentException("未知用戶預設 ID: $id");
}
$data = self::$presets[$id];
return new User($data['name'], $data['age'], $data['group']);
}
}
// 業務調用極簡
$user = UserFactory::create(0);
echo $user->getName(); // 小明
| 維度 | 直接 new | 工廠模式 |
|---|---|---|
| 參數變更影響面 | 全項目掃描修改 | 僅修改工廠類 |
| 創建邏輯複用 | 不可複用 | 集中管理,可擴展策略 |
| 測試友好度 | 難以 Mock | 可注入 Mock Factory |
| 配置外部化 | 代碼硬編碼 | 支援 JSON/YAML/DB 動態加載 |
| 單一職責原則 | 業務邏輯混雜創建細節 | 創建職責獨立 |
當預設不足以覆蓋所有場景,支援動態參數覆蓋:
public static function create(int $id, array $override = []): IUser {
$data = array_merge(self::$presets[$id] ?? [], $override);
return new User($data['name'], $data['age'], $data['group']);
}
// 用法
$teacher = UserFactory::create(0, ['group' => '教師', 'age' => 35]);
IUser),而非具體實現,便於後續替換實現類。config/users.php、Redis 或 DB,實現無發布變更參數。new 更簡潔。工廠模式不是為了「炫技」,而是為了將變化隔離在單一位置。當類的創建邏輯涉及參數組裝、依賴注入、配置讀取、策略選擇等復雜度時,引入工廠類是性價比最高的重構手段。從 new User(...) 到 UserFactory::create(...),代碼行數微增,維護性質變。