想象一下,我有一堆可以进行日志记录的类,所以我创建了一个记录器接口和几个实现(写入文件,stdout,db等),但有时我不知道#39; t关心记录这些消息,所以我做了一个实现,只是忽略了所有的消息。
现在这有助于避免if
并且只使用$this->logger->write($message)
,但我仍然必须每次都注入虚拟记录器。
在构造函数中执行诸如$this->logger = $logger ? $logger : new DummyLogger()
之类的操作会有什么害处。
我通常不会在构造函数中工作,但这种东西看起来并不太危险。
你会选择这种方法吗?
答案 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();