假设我们有一个日志记录接口:
interface Logger {
function log($message);
}现在说我们有两个Logger接口的具体实现:FileLogger和和ConsoleLogger。
class FileLogger implements Logger {
public function log($message) {
// 将日志消息追加到某些文件
}
}
class ConsoleLogger implements Logger {
public function log($message) {
// 将消息记录到控制台
}
}现在,如果您定义了一些Foo您还希望能够执行日志记录任务的类,则可以执行以下操作:
class Foo implements Logger {
private $logger;
public function setLogger(Logger $logger) {
$this->logger = $logger;
}
public function log($message) {
if ($this->logger) {
$this->logger->log($message);
}
}
}Foo现在也是Logger,但其功能取决于Logger通过传递给它的实现setLogger()。如果现在我们希望类Bar也具有此日志记录机制,则必须在Bar类中复制此逻辑。
无需复制代码,可以定义一个特征:
trait LoggableTrait {
protected $logger;
public function setLogger(Logger $logger) {
$this->logger = $logger;
}
public function log($message) {
if ($this->logger) {
$this->logger->log($message);
}
}
}现在,我们已经在特征中定义了逻辑,我们可以使用特征将逻辑添加到Foo和Bar类中:
class Foo {
use LoggableTrait;
}
class Bar {
use LoggableTrait;
}并且,例如,我们可以使用这样的Foo类:
$foo = new Foo();
$foo->setLogger( new FileLogger() );
//注意我们如何使用特征作为“代理”来调用Foo实例上的Logger的log方法
$foo->log('my beautiful message');