在PHP中使用Decorator模式动态实例化类
通常,在使用decorator模式时,我通常直接实例化类,一个在另一个中:在PHP中使用Decorator模式动态实例化类,php,arrays,design-patterns,Php,Arrays,Design Patterns,通常,在使用decorator模式时,我通常直接实例化类,一个在另一个中: abstract class Handler { public function __construct(Handler $handler = null) { $this->handler = $handler; } abstract public function handle(); } class FirstHandler extends Handler {
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个处理程序,您可以看到代码将开始缩进太多,使其难以阅读,特别是如果链中不同的处理程序没有“FirstHandler”、“SecondHandler”这样简单的名称,但总体来说,它看起来并不好
我想知道是否有一种方法可以动态实例化这些类,方法是将它们放在一个数组中,然后遍历数组,并将数组中的n+1元素作为构造函数参数传递给数组中的第n个元素
我有这样的想法:
$chain = null;
$links = [
FirstHandler::class,
SecondHandler::class,
ThirdHandler::class,
FourthHandler::class
];
foreach ($links as $index => $link) {
$chain = new $link(new $links[$index + 1]());
}
您可能知道第一个问题是,$chain
在每次调用时都被覆盖。第二个问题是,即使使用循环,我仍然必须手动将每个处理程序传递到链中,而真正要做的就是以原始方式创建链四次,这实际上更糟。第三个问题是,最终我会得到一个越界异常
有没有一种方法可以按照我的意图(可能是某种递归调用)动态实例化此链,或者我注定要像以前那样执行此操作?下面是一个在构造函数中使用数组的示例,并使用
array\u shift
从列表中删除第一项<代码>处理程序::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
// }
// }
// }
// }
第二个版本,带有_构造类型提示
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 );
下面是一个在构造函数中使用数组并使用
array\u shift
从列表中删除第一项的示例<代码>处理程序::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
// }
// }
// }
// }
第二个版本,带有_构造类型提示
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 );
你要发明依赖注入哈哈。你能举个例子给我演示一下吗?我想了解我是如何做到这一点的。这包括随时可用的组件,如DI容器等。所有的例子都在这里,你将发明依赖注入哈哈。你能举个例子给我演示一下吗?我想了解我是如何做到这一点的。这包括随时可用的组件,如DI容器等。所有的例子都在这里。这是一个非常好的答案,非常接近于解决我的需要。对我来说唯一的问题是,这将要求我提升对构造函数类型提示的限制,我使用构造函数总是确保类型
Handler
的实例总是被传递。请使用Handler::handlerFactory($classes)
使用array\u reverse($chain)尝试我的第二个版本
这是一个非常好的答案,非常接近于解决我的需求。对我来说唯一的问题是,这将要求我提升对构造函数类型暗示的限制,我使用构造函数总是确保类型Handler
的实例总是被传递。请使用Handler::handlerFactory($classes)
尝试我的第二个版本,使用array\u reverse($chain)