Hi,
I stumbled upon a problem and I wanted to hear what others think about it.
I have the following code:
class A {
public function doSomething() {
$externalEventsSource = $this->getExternalEventsSource();
$externalEventsSource->addEventListener(
'EVENT',
array( 'callback' => array( $this, 'onEvent' ) )
);
}
public function getExternalEventsSource() {
// retrieves an object that dispatches certain (external) events
}
public function onEvent( $event ) {
// do something
}
}
// extend so that BaseDecorator gains the A type
class BaseDecorator extends A {
protected $a;
public function __construct( A $a ) {
$this->_a = $a;
}
public function doSomething() {
$this->_a->doSomething();
}
public function getExternalEventsSource() {
return $this->_a->getExternalEventsSource();
}
public function onEvent( $event ) {
$this->_a->onEvent( $event );
}
public function __call( $method, $args ) {
// calls to nonexistent methods are routed to the decorated object
return call_user_func_array( array( $this->_a, $method ), $args );
}
}
$d = new BaseDecorator( new A() );
$d->doSomething();
Now, the problem is that I want class A to attach to externalEventsSource’s events with the decorator’s onEvent() method to benefit from the enhanced behavior the decorator provides.
The above example is simplified. I do not want to rewrite BaseDecorator::doSomething() method because in the real life situation there’s a lot of code in there which I would end up duplicating for every decorator I add. More, if my decorated class listens to more than one events I may want to attach with only SOME of the decorator’s methods to the externalEventsSource object.
What suggestions do you have?
A solution I’ve considered is adding a setContext( $context ) method to A. This would result in:
class A {
public function setContext( $context ) {
$this->_context = $context;
}
public function doSomething() {
$context = ( $this->_context !== null ? $this->_context : $this );
$externalEventsSource = $this->getExternalEventsSource();
$externalEventsSource->addEventListener(
'EVENT',
array( 'callback' => array( $context, 'onEvent' ) )
);
}
public function getExternalEventsSource() {
// retrieves an object that dispatches certain (external) events
}
public function onEvent( $event ) {
// do something
}
}
// extend so that BaseDecorator gains the A type
class BaseDecorator extends A {
protected $a;
public function __construct( A $a ) {
$a->setContext( $this );
$this->_a = $a;
}
public function setContext( $context ) {
$this->_a->setContext( $context );
}
public function doSomething() {
$this->_a->doSomething();
}
public function getExternalEventsSource() {
return $this->_a->getExternalEventsSource();
}
public function onEvent( $event ) {
$this->_a->onEvent( $event );
}
public function __call( $method, $args ) {
// calls to nonexistent methods are routed to the decorated object
return call_user_func_array( array( $this->_a, $method ), $args );
}
}
What do you think about this solution?
Thanks in advance.