通常,在使用装饰器模式时,我通常直接实例化类,一个在另一个中:
abstract class Handler
{
public function __construct(Handler $handler = null)
{
$this->handler = $handler;
}
abstract public function handle();
}
class FirstHandler extends Handler
{
public function handle()
{
// Just calls the next guy in the chain. Obviously, this isn't doing anything, it's just for example sake.
$this->handler->handle();
}
}
// ... and so on with the SecondHandler, ThirdHandler, FourthHandler
$chain = new FirstHandler(
new SecondHandler(
new ThirdHandler(
new FourthHandler()
)
)
);
$chain->handle();
然而,随着链条增长的可能性,或许是20个处理程序,您可以看到代码会开始缩进太多并且难以阅读,特别是如果链中的不同处理程序不在&#39 ; t的名称简单如" FirstHandler"," SecondHandler",但总的来说,它看起来并不好。
我想知道是否有办法通过将类放在数组中来动态实例化类,并迭代数组并将数组中的 n + 1 元素作为构造函数参数传递给数组中的 nth 元素。
我心中有这样的想法:
$chain = null;
$links = [
FirstHandler::class,
SecondHandler::class,
ThirdHandler::class,
FourthHandler::class
];
foreach ($links as $index => $link) {
$chain = new $link(new $links[$index + 1]());
}
您可能会告诉第一个问题是每次调用都会覆盖$chain
。第二个问题是,即使使用循环,我仍然必须手动将每个处理程序传递到链中,所有真正做的就是创建链原始方式四次,这实际上更糟糕。第三个问题是最终我会得到一个超出范围的例外。
有没有办法动态实例化这个链,如我的意图所示(也许是一种递归调用)或者我注定要像以前那样做它?
答案 0 :(得分:0)
以下是在构造函数中使用数组的示例,并使用array_shift
删除列表中的第一个项目。 Handler::makeChain( $classes )
让球滚动......
class Handler
{
private $handler;
public function __construct( $chain )
{
if( empty( $chain ) === false )
{
$this->handler = static::makeChain( $chain );
}
}
public static function makeChain( $chain )
{
$class = array_shift( $chain );
return new $class( $chain );
}
}
class FirstHandler extends Handler{}
class SecondHandler extends Handler{}
class ThirdHandler extends Handler{}
class FourthHandler extends Handler{}
$classes = array(
'FirstHandler',
'SecondHandler',
'ThirdHandler',
'FourthHandler',
);
$handler = Handler::makeChain( $classes );
var_dump( $handler );
// object(FirstHandler)#77 (1) {
// ["handler":"Handler":private]=>
// object(SecondHandler)#78 (1) {
// ["handler":"Handler":private]=>
// object(ThirdHandler)#79 (1) {
// ["handler":"Handler":private]=>
// object(FourthHandler)#80 (1) {
// ["handler":"Handler":private]=>
// NULL
// }
// }
// }
// }
带有__construct typehint的第二个版本
class Handler
{
private $handler;
public function __construct( Handler $injectedHandler = null )
{
if( $injectedHandler )
{
$this->handler = $injectedHandler;
}
}
public static function handlerFactory( $chain )
{
$instance = null;
foreach( array_reverse( $chain ) as $class )
{
$instance = new $class( $instance );
}
return $instance;
}
}
class FirstHandler extends Handler{}
class SecondHandler extends Handler{}
class ThirdHandler extends Handler{}
class FourthHandler extends Handler{}
$classes = array(
'FirstHandler',
'SecondHandler',
'ThirdHandler',
'FourthHandler',
);
$handler = Handler::handlerFactory( $classes );
var_dump( $handler );