setter 注入
依賴關係也可以由 setter 注入。
interface Logger {
public function log($message);
}
class Component {
private $logger;
private $databaseConnection;
public function __construct(DatabaseConnection $databaseConnection) {
$this->databaseConnection = $databaseConnection;
}
public function setLogger(Logger $logger) {
$this->logger = $logger;
}
public function core() {
$this->logSave();
return $this->databaseConnection->save($this);
}
public function logSave() {
if ($this->logger) {
$this->logger->log('saving');
}
}
}
當類的核心功能不依賴於依賴工作時,這尤其有趣。
在這裡,唯一需要的依賴是 DatabaseConnection
所以它在建構函式中。Logger
依賴項是可選的,因此不需要是建構函式的一部分,使類更容易使用。
請注意,使用 setter 注入時,最好擴充套件功能而不是替換它。設定依賴項時,沒有任何事情可以確認依賴項在某些時候不會發生變化,這可能會導致意外結果。例如,首先可以設定 FileLogger
,然後可以設定 MailLogger
。這打破了封裝並使得日誌很難找到,因為我們正在替換依賴。
為了防止這種情況,我們應該使用 setter 注入新增依賴項,如下所示:
interface Logger {
public function log($message);
}
class Component {
private $loggers = array();
private $databaseConnection;
public function __construct(DatabaseConnection $databaseConnection) {
$this->databaseConnection = $databaseConnection;
}
public function addLogger(Logger $logger) {
$this->loggers[] = $logger;
}
public function core() {
$this->logSave();
return $this->databaseConnection->save($this);
}
public function logSave() {
foreach ($this->loggers as $logger) {
$logger->log('saving');
}
}
}
像這樣,每當我們使用核心功能時,即使沒有新增記錄器依賴項也不會中斷,即使可以新增另一個記錄器,也會使用新增的任何記錄器。我們正在擴充套件功能而不是替換它。