构造函数注入 - 如果构造函数中没有提供,则可以使用新的null对象吗?

时间:2011-11-30 10:08:56

标签: php language-agnostic dependency-injection

想象一下,我有一堆可以进行日志记录的类,所以我创建了一个记录器接口和几个实现(写入文件,stdout,db等),但有时我不知道#39; t关心记录这些消息,所以我做了一个实现,只是忽略了所有的消息。

现在这有助于避免if并且只使用$this->logger->write($message),但我仍然必须每次都注入虚拟记录器。

在构造函数中执行诸如$this->logger = $logger ? $logger : new DummyLogger()之类的操作会有什么害处。

我通常不会在构造函数中工作,但这种东西看起来并不太危险。

你会选择这种方法吗?

2 个答案:

答案 0 :(得分:1)

在回答您的问题之前,我建议您重新考虑您的Logger架构。记录始终是相同的。你在某个地方写了一条消息。唯一不同的是 somewhere 部分,因此将Logger分离为通用Logger和各种Writer是有意义的。这样可以提供更大的灵活性,例如,您可以使用Composite模式一次写入多个Logger。

关于您的问题:通常,您希望避免将依赖项硬编码到代码中,因为它会直接影响可测试性和可重用性,例如:您的Logger只能与此特定的NullWriter一起使用。如果您要分发Logger,您还必须分发Writer。

然而,假设您只会将整个Logers包装的Logger分发,并且您还提供了进行ctor注入的方法,我不会发现很多问题。如果需要,你仍然可以换掉Writer,所以一切都很好。

当我们谈论interpackage依赖时,它有些不同。你会想要避免这些,例如数据库包中的类不应该依赖于Logger包中的类。

从Logger内部分配NullWriter的另一种方法是使用LoggerFactory创建Logger和指定的Writer,注入Writer并返回Logger。

答案 1 :(得分:1)

我不会选择这种方法,因为它是一种很难的依赖和额外的课程。有一些模式可以避免这些问题 - 并解决你的困境。

您可以实现观察者模式的版本,例如:

class Loggable
{
    protected $aLoggers = array();

    public function addLogger(Logger $oLog) {
        $this->aLoggers[] = $oLog;
    }

    public function invokeLoggers($sMessage) {
        foreach($this->aLoggers as $oLog) {
            $oLog->write($sMessage);
        }
    }
}

这些函数应该在一个单独的类中,以便任何使用记录器的类都可以扩展此功能。您现在可以选择不添加记录器,因此调用将不执行任何操作 - 或者根本不扩展原始类。

class SomeClass extends Loggable
{
    public function doSomething()
    {
        // Some code
        $this->invokeLoggers();
    }
}

$oSomeClass = new SomeClass();
$oSomeClass->addLogger(new FileLogger());
$oSomeClass->addLogger(new DatabaseLogger());
$oSomeClass->addLogger(new EmailLogger());
$oSomeClass->doSomething();