本文通過「超人需要超能力」的生動隱喻,層層遞進講解面向對象設計中依賴產生、工廠模式、依賴注入(DI)至 IoC 容器的演進邏輯,並關聯 Laravel 服務容器實現。
class Superman {
protected $power;
public function __construct() {
$this->power = new Power(999, 100); // 硬編碼依賴
}
}
超人與具體超能力強耦合,新增/變更能力需修改 Superman 類,違反開閉原則。
class SuperModuleFactory {
public function makeModule($name, $options) {
switch ($name) {
case 'Flight': return new Flight($options[0], $options[1]);
case 'Force': return new Force($options[0]);
case 'Shot': return new Shot($options[0], $options[1], $options[2]);
}
}
}
class Superman {
public function __construct(array $modules) {
$factory = new SuperModuleFactory;
foreach ($modules as $name => $opts) {
$this->power[] = $factory->makeModule($name, $opts);
}
}
}
依賴從「多個具體類」轉移到「單一工廠」,但工廠類本身成為新的耦合點,擴展需修改工廠代碼。
定義接口契約,外部注入實現:
interface SuperModuleInterface {
public function activate(array $target);
}
class XPower implements SuperModuleInterface { /* ... */ }
class UltraBomb implements SuperModuleInterface { /* ... */ }
class Superman {
protected $module;
public function __construct(SuperModuleInterface $module) {
$this->module = $module; // 構造器注入
}
}
// 使用
$superman = new Superman(new XPower);
DI 核心:依賴不由類內部創建,而是由外部通過構造器、Setter 或接口注入。實現了「高層模塊不依賴低層模塊,雙方依賴抽象」。
class Container {
protected $binds = [];
protected $instances = [];
public function bind($abstract, $concrete) {
if ($concrete instanceof Closure) {
$this->binds[$abstract] = $concrete;
} else {
$this->instances[$abstract] = $concrete;
}
}
public function make($abstract, $parameters = []) {
if (isset($this->instances[$abstract])) {
return $this->instances[$abstract];
}
array_unshift($parameters, $this);
return call_user_func_array($this->binds[$abstract], $parameters);
}
}
// 綁定腳本
$container = new Container();
$container->bind('superman', function($c, $moduleName) {
return new Superman($c->make($moduleName));
});
$container->bind('xpower', fn($c) => new XPower);
$container->bind('ultrabomb', fn($c) => new UltraBomb);
// 自動解析依賴並生產
$superman_1 = $container->make('superman', ['xpower']);
$superman_2 = $container->make('superman', ['ultrabomb']);
// Superman Object ( [module:protected] => XPower Object ( ) )
容器通過 bind 註冊解析邏輯,make 時遞歸解析依賴。真正的 IoC 容器(如 Laravel)利用 反射(Reflection) 自動分析構造器參數類型提示,實現零配置自動注入。
register)與啟動(boot),確保依賴就緒。Route::get() 映射到容器解析的 Illuminate\Routing\Router 實例。理解 IoC/DI 不僅是掌握框架用法,更是掌握可維護、可測試、可擴展的面向對象設計精髓。