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 />

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

  1. 3 Август 2009 в 23:39 | #1
    ахуенно! вот она где модульность, а не в switch($_GET['module']) ....
  2. 3 Август 2009 в 23:41 | #2
    switch($_GET['module'])
    ИМХО это из разряда "моя первая цмс"
  3. 3 Август 2009 в 23:42 | #3
    @CTAPbIu_MABP
    посмотри на ДЛЕ 8.5 ...
  4. 3 Август 2009 в 23:43 | #4
    моя восьмая с половиной цмс, а я все еще не научился писать hello word :)
  5. 3 Август 2009 в 23:54 | #5
    CTAPbIu_MABP :
    моя восьмая с половиной цмс, а я все еще не научился писать hello word :)

    это факт ..
  6. aiveeee
    8 Август 2009 в 11:40 | #6
    круто!11
  1. Пока что нет уведомлений.