设置程序也可以注入依赖项。
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可以首先设置a ,然后再MailLogger设置a。这会破坏封装并使日志难以查找,因为我们正在替换依赖项。
为了防止这种情况,我们应该在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');
}
}
}这样,每当我们使用核心功能时,即使没有添加记录器依赖项,它也不会中断,并且即使可以添加另一个记录器,添加的记录器也将被使用。我们正在扩展功能,而不是取代它。