I am using a decorator pattern to add style and options to an output stream (console).
It’s an console app that adds color to the command line output. The
decorator adds the color. The condition in the ClientClass is that
if an error occurred then decorate with red text and if no error occurred then decorate with green text. The color
decorator therefore has optional calls that only the ClientClass
can know about.* Copy of the OP’s comment on one of the answers
The problem I have is this: I am passing in my decorator to a class via the constructor. But the decorated object requries that I call two methods that are not in the base class i.e. that being decorated.
Is this bad? Shouldnt i only be calling those methods which are available in all decorated classes?
As an example:
<?php
abstract class MyAceBaseClass
{
abstract function doYourThing();
}
class MyAceBaseClassDecoratorA extends MyAceBaseClass
{
protected $aceBaseClass;
protected $amount = 0;
public function __construct($aceBaseClass)
{
$this->_aceBaseClass = $aceBaseClass;
}
public function doYourThing()
{
$result = $aceBaseClass + $this->amount;
return $result;
}
public function decoratorFunctionA()
{
$this->amount = 10;
}
public function decoratorFunctionB()
{
//----
}
}
class ClientClass
{
private $aceObject;
public function __construct(MyAceBaseClass $aceObject)
{
$this->aceObject = $aceObject;
}
public function run()
{
if ($someCondition) {
$this->aceObject->decoratorFunctionA();
$this->aceObject->decoratorFunctionB();
}
$result = $this->aceObject->doYourThing();
echo $result;
}
}
So as you can see, the client class needs to call decoratorFunctionA and decoratorFunctionB (which are only availble in the decorator class) before it can call the abstract method doYourThing() available to all classes extending MyAceBaseClass. This feels wrong.
I think the decorator implementation is correct but now i am stuck with this other problem
How can i resolve this?
The client class might not need both decoratorFunctionA() and decoratorFunctionB() called, it might only need 1 or none so I cant simply call these automatically in the doYourThing call.
A possibility is to have an interface for MyAceBaseClassDecoratorA but then i am kind of defeating the purpose of using the decorator in the first place.
You can’t call methods not specified by the interface you’re expecting:
MyAceBaseClass(as @ctrahey pointed out).Also, if I read it correctly, you seem to be mixing the things up. Who’s decorating who in this case?
If the purpose of the Decorator Pattern is to add functionality to an existing object without subclassing (in other words, without saying that an object “is a”), the decorator must have a protected property with the decorated object. It seems like that it’s your
ClientClassthat’s decorating what you calledMyAceBaseClassDecoratorA.IMO, it should be something along this lines:
EDITED:
As for your explanation in the comments, here’s what you should do:
So, you’ll not call
$this->aceObject->decoratorFunctionA();or$this->aceObject->decoratorFunctionB();outside of the decorator as you have done in theClientClass.Instead, you should provide the decorated object with the functionality injected into the
doYourThing()method before calling the$ClientClass->aceObject->doYourThing()method.If there’s an error, then you’ll decorate it with the
RedTextDecorator, if everything went well, than you’ll, instead, decorate it with theGreenTextDecorator.