当我想设计一个实现可以提供任何功能子集的组件时,我会遇到同样的问题。
以下是简单消息队列系统的示例:
根据这些要求,我的模型可能如下:
interface QueueInterface
{
function push($message);
function poll();
}
// If a message is simply "pushed" then the $scheduleTime is now
interface ScheduledQueueInterface /* extends QueueInterface */
{
function schedule($message, DateTime $scheduleTime);
}
// If a message is simply "pushed" then the channel is NULL
interface NamedQueueInterface /* extends QueueInterface */
{
function pushInChannel($message, $channel);
function pollFromChannel($channel);
}
现在,由于我的vanilla QueueInterface是内容不可知的,我应该能够通过在消息字符串中嵌入通道名来编写装饰器来模拟命名通道:
// Channel are concatenated on the front of the message and separated by a NULL char
class NamedQueueDecorator implements NamedQueueInterface, QueueInterface
{
/**
*
* @var QueueInterface
*/
protected $queue;
function pushInChannel($message, $channel)
{
$this->queue->push("$channel\0$message");
}
function pollFromChannel($channel)
{
// ???
}
function push($message)
{
$this->queue->push("\0$message");
}
function poll()
{
return substr($message = $this->queue->poll(), strpos($message, "\0") + 1);
}
}
(我的例子不是很好,因为我不知道如何pollFromChannel()
与我的装饰师,但想象这是可能的和直截了当的)
现在,我的问题是:如果装饰器中的内部队列实现ScheduledQueueInterface
怎么办?
我应该创建一个仅实现QueueInterface
的装饰器和另一个同时实现ScheduledQueueInterface
的装饰器吗?
我应该只创建一个实现实现任何"功能的装饰器"存在?如果我这样做,那么没有实现功能的内部队列呢? (例如$this->queue->schedule($message, $scheduledTime)
会失败)
Http客户端实现相同的功能接口也遇到同样的问题:他们可以实现许多功能(身份验证,缓存控制,重定向......)但是如果有一个Http客户端但我们希望能够实现抛开一个功能并装饰一个没有这个功能的Http客户端来丰富它。
那么你知道一种提出一系列功能和部分实现的方法吗?"功能补丁"同时尊重接口?