Pattern: Decorator

Сколько раз обещаю себе больше не писать на PHP, и всеравно пишу. Вот и недавно разродился небольшим классом реализующим шаблон декоратор.


class Decorator {
	protected $obj;
	public function __construct($name,$args=null){
		if (is_object($name)) {
			$this->obj = $name;
		} else if($args) {
			$reflection = new ReflectionClass($name);
			$this->obj = $reflection->newInstanceArgs($args);
		} else {
			$this->obj = new $name;
		}
	}

	public function __call($name,$args){
		if($args)
			return call_user_func_array(array($this->obj,$name), $args);
		else
			return $this->obj->{$name}();
	}
}

Все началось как пример одному долбаёбу на форуме, а закончилось как небольшой но прикольный класс. Естественно сначала я пару раз переписал пример, потом потестил его на локальном сервере и только потом написал эту статью, так что в классе есть небольшие изменения.

На вопрос нах вообще нуже декоратор я отвечать не буду — читайте вики или еще что-то. А вот на вопрос как это работает отвечу. Для начала создадим класс который нужно декорировать.


class MyClass {
	private $property;
	public function __construct($property){
		$this->property = $property;
	}
	public function printMethodName(){
		echo __METHOD__;
	}
	
	public function printMyArgument($arg){
		echo $arg;
	}
	
	public function printMyProperty(){
		echo $this->property;
	}
	public function myDecoratedMethod(){
		echo "Decorated Method!";
	}
}

Как понятно методы особой смысловой нагрузки не несут, а только показывают что были вызваны именно они. Теперь создадим класс производный от декоратора, который будет декорировать последний метод класса MyClass.


class ConcreteDecorator extends Decorator {
	public function myDecoratingMethod(){
		return $this->myDecoratedMethod();
	}
}

Теперь это все можно использовать примерно вот таким образом:


$myObj = new ConcreteDecorator("MyClass", array("String passed via constructor"));

$myObj->printMyProperty();
$myObj->printMethodName();
$myObj->printMyArgument("String passed via printMyArgument");
$myObj->myDecoratingMethod();

Но что-то как-то некрасиво получается, надо бы добавить в после каждого метода обрыв строки, для этого создадим еще один декоратор:


class MyNewLineDecorator extends Decorator {
	public function __call($name,$args){
		parent::__call($name,$args);
		echo "<br />";
	}
}

И добавим его в код.


$myObj = new ConcreteDecorator("MyClass", array("String passed via constructor"));
$myObj = new MyNewLineDecorator($myObj);

$myObj->printMyProperty();
$myObj->printMethodName();
$myObj->printMyArgument("String passed via printMyArgument");
$myObj->myDecoratingMethod();

В результате получаем:

String passed via constructor<br />
MyClass::printMethodName<br />
String passed via printMyArgument<br />
Decorated Method!<br />

Приятного использования.

6 Комментарии “Pattern: Decorator

Комментарии закрыты