<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Разработка &#187; проектирование</title>
	<atom:link href="http://www.job-blog.bullgare.ru/tag/%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.job-blog.bullgare.ru</link>
	<description>о программировании и работе</description>
	<lastBuildDate>Wed, 08 Feb 2012 09:39:48 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
		<item>
		<title>Пример архитектуры таблиц иерархических данных</title>
		<link>http://www.job-blog.bullgare.ru/2009/09/%d0%bf%d1%80%d0%b8%d0%bc%d0%b5%d1%80-%d0%b0%d1%80%d1%85%d0%b8%d1%82%d0%b5%d0%ba%d1%82%d1%83%d1%80%d1%8b-%d1%82%d0%b0%d0%b1%d0%bb%d0%b8%d1%86-%d0%b8%d0%b5%d1%80%d0%b0%d1%80%d1%85%d0%b8%d1%87%d0%b5/</link>
		<comments>http://www.job-blog.bullgare.ru/2009/09/%d0%bf%d1%80%d0%b8%d0%bc%d0%b5%d1%80-%d0%b0%d1%80%d1%85%d0%b8%d1%82%d0%b5%d0%ba%d1%82%d1%83%d1%80%d1%8b-%d1%82%d0%b0%d0%b1%d0%bb%d0%b8%d1%86-%d0%b8%d0%b5%d1%80%d0%b0%d1%80%d1%85%d0%b8%d1%87%d0%b5/#comments</comments>
		<pubDate>Sun, 13 Sep 2009 15:06:57 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Базы данных]]></category>
		<category><![CDATA[проектирование]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[архитектура]]></category>
		<category><![CDATA[примеры]]></category>

		<guid isPermaLink="false">http://www.job-blog.bullgare.ru/?p=238</guid>
		<description><![CDATA[http://dev.mysql.com/tech-resources/articles/hierarchical-data.html]]></description>
			<content:encoded><![CDATA[<p>http://dev.mysql.com/tech-resources/articles/hierarchical-data.html</p>
]]></content:encoded>
			<wfw:commentRss>http://www.job-blog.bullgare.ru/2009/09/%d0%bf%d1%80%d0%b8%d0%bc%d0%b5%d1%80-%d0%b0%d1%80%d1%85%d0%b8%d1%82%d0%b5%d0%ba%d1%82%d1%83%d1%80%d1%8b-%d1%82%d0%b0%d0%b1%d0%bb%d0%b8%d1%86-%d0%b8%d0%b5%d1%80%d0%b0%d1%80%d1%85%d0%b8%d1%87%d0%b5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Паттерн Decorator (Wrapper) в php</title>
		<link>http://www.job-blog.bullgare.ru/2009/07/%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd-decorator-wrapper-%d0%b2-php/</link>
		<comments>http://www.job-blog.bullgare.ru/2009/07/%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd-decorator-wrapper-%d0%b2-php/#comments</comments>
		<pubDate>Sat, 25 Jul 2009 18:30:28 +0000</pubDate>
		<dc:creator>bullgare</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[проектирование]]></category>
		<category><![CDATA[паттерн]]></category>
		<category><![CDATA[паттерн Decorator]]></category>
		<category><![CDATA[паттерны проектирования]]></category>
		<category><![CDATA[структурный паттерн]]></category>

		<guid isPermaLink="false">http://www.job-blog.bullgare.ru/?p=36</guid>
		<description><![CDATA[Паттерн &#171;Decorator&#187; (&#171;Wrapper&#187;) динамически добавляет объекту новые обязанности. Является гибкой альтернативой подклассам, расширяющим базовый класс. Схема следующая: Поместить целевой объект в другой объект, называемый декоратором, который большинство обращений переводит к переданному объекту, а часть (особенности) реализует самостоятельно. Могут вкладываться друг в друга по цепочке. Интерфейс декоратора и декорируемого объекта должны совпадать. Отличается от паттерна &#171;Strategy&#187; [...]]]></description>
			<content:encoded><![CDATA[<p>Паттерн &laquo;Decorator&raquo; (&laquo;Wrapper&raquo;) динамически добавляет объекту новые обязанности.<br />
Является гибкой альтернативой подклассам, расширяющим базовый класс.<br />
<span id="more-36"></span></p>
<p>Схема следующая:<br />
Поместить целевой объект в другой объект, называемый декоратором, который большинство обращений переводит к переданному объекту, а часть (особенности) реализует самостоятельно.<br />
Могут вкладываться друг в друга по цепочке.<br />
Интерфейс декоратора и декорируемого объекта должны совпадать.</p>
<p>Отличается от паттерна &laquo;Strategy&raquo; тем, что в последнем всё наоборот &#8211; главным является целевой объект, который распределяет обращения &laquo;расширениям&raquo;.</p>
<blockquote><p>
Листинг1. Decorator.php (PHP 5.2.5)
</p></blockquote>
<pre class="code">
&lt;?
//интерфейс, который будут реализовывать все: и целевой класс, и все декораторы
interface ClassInterface
{
	public function method1();

	public function method2();
}

//целевой класс
class TargetClass implements ClassInterface
{
	public function method1()
	{
		echo 'called "method1"';
	}

	public function method2()
	{
		echo '"called method2"';
	}
}

//от этого класса будут наследоваться все декораторы
abstract class AbstractTargetDecorator implements ClassInterface
{
	private $_componentObject = null;

	//т.к. реализуем интерфейс
	public function method1()
	{
		$this->_componentObject->method1();
	}

	public function method2()
	{
		$this->_componentObject->method2();
	}

	public function __construct(ClassInterface $componentObject)
	{
		$this->_componentObject = $componentObject;
	}

	//для вызова методов декораторов по цепочке
	public function __call($methodName, $arguments)
	{
		//чтобы не было ошибок; можно кидать Exception
		if (method_exists($this->_componentObject, $methodName))
			call_user_func_array(array($this->_componentObject, $methodName), $arguments);
	}

	public function abstractTargetDecoratorMethod()
	{
		echo 'called "abstractTargetDecoratorMethod"';
	}

}

//первый декоратор
class TargetDecorator1 extends AbstractTargetDecorator
{
	public function decorator1Method()
	{
		echo 'called "decorator1Method"';
	}
}

//второй декоратор
class TargetDecorator2 extends AbstractTargetDecorator
{
	public function decorator2Method()
	{
		echo 'called "decorator2Method"';
	}
}

//Использование

$decoratedObject = new TargetDecorator2(new TargetDecorator1(new TargetClass()));
//$decoratedObject = new TargetDecorator1(new TargetDecorator2(new TargetClass()));
//$decoratedObject = new TargetDecorator2(new TargetClass());
$decoratedObject->decorator1Method();
$decoratedObject->decorator2Method();
$decoratedObject->method1();
$decoratedObject->method2();
$decoratedObject->abstractTargetDecoratorMethod();

?&gt;
</pre>
<p>Ну, вообще-то, что совсем необязательно <em>AbstractTargetDecorator</em>&#8216;у реализовывать интерфейс <em>ClassInterface</em>. Это сделано для того, чтобы потомки могли друг в друга вкладываться. Хотя это и не нужно для паттерна декоратор.<br />
Можно применить в следующем примере:<br />
Есть 2 типа статей, которые состоят из нескольких типов модулей каждый. Причём эти модули одинаковы для обоих типов статей за исключением механизма их хранения. При этом все они наследуются от класса <em>module</em>.<br />
Специфичность ситуации в том, что данные сохраняются в виде сериализованных объектов модулей, и второй тип статей вводился намного позже первого (накопилось много сохранённых данных).<br />
При этом наследовать каждый модуль второго типа статей от соответствующего модуля первого типа нехорошо, т.к. механизм хранения один для всех модулей одного типа.<br />
Именно в этом случае мог бы помочь паттерн Декоратор: для каждого типа статей создаётся класс, отвечающий за сохранение в зависимости от типа статьи, и декорирующий исходный объект.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.job-blog.bullgare.ru/2009/07/%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd-decorator-wrapper-%d0%b2-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Паттерны проектирования в php</title>
		<link>http://www.job-blog.bullgare.ru/2009/07/%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd%d1%8b-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d1%8f-%d0%b2-php/</link>
		<comments>http://www.job-blog.bullgare.ru/2009/07/%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd%d1%8b-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d1%8f-%d0%b2-php/#comments</comments>
		<pubDate>Fri, 24 Jul 2009 08:02:49 +0000</pubDate>
		<dc:creator>bullgare</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[проектирование]]></category>
		<category><![CDATA[паттерн]]></category>
		<category><![CDATA[паттерн Factory]]></category>
		<category><![CDATA[паттерн Observer]]></category>
		<category><![CDATA[паттерн Singleton]]></category>
		<category><![CDATA[паттерн Strategy]]></category>
		<category><![CDATA[паттерн Сhain-of-command]]></category>
		<category><![CDATA[паттерны проектирования]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[шаблон]]></category>

		<guid isPermaLink="false">http://www.job-blog.bullgare.ru/?p=3</guid>
		<description><![CDATA[Введение Шаблоны проектирования были представлены общественности в книге Design Patterns (Erich Gamma, Richard Helm, Ralph Johnson и John Vlissides (известные как &#171;банда четырёх&#187;)). Основная концепция, представленная во введении, была простой. За годы разработки программного обеспечения Gamma и сотоварищи открыли определённые шаблоны (&#171;паттерны&#187;) проектирования, как и архитекторы, строящие дома и здания, могут разработать шаблоны расположения уборных [...]]]></description>
			<content:encoded><![CDATA[<h3>Введение</h3>
<p>Шаблоны проектирования были представлены общественности в книге Design Patterns (Erich Gamma, Richard Helm, Ralph Johnson и John Vlissides (известные как &laquo;банда четырёх&raquo;)). Основная концепция, представленная во введении, была простой. За годы разработки программного обеспечения Gamma и сотоварищи открыли определённые шаблоны (&laquo;паттерны&raquo;) проектирования, как и архитекторы, строящие дома и здания, могут разработать шаблоны расположения уборных или обустройства кухни. Используя эти шаблоны, или паттерны проектирования, можно проектировать качественные здания быстрее. То же применимо и к разработке программного обеспечения.<br />
<span id="more-3"></span><br />
Паттерны проектирования представляют не только удобный способ для более быстрой разработки надёжного ПО, но и способ для инкапсуляции больших идей в понятных терминах. К примеру, можно говорить о написании системы сообщений для обеспечения слабой связности, а можно &#8211; о паттерне observer, а означать это будет одно и то же.</p>
<p>Сложно продемонстрировать значение паттернов на небольших примерах. Они при этом часто выглядят как излишнее усложнение кода, потому что проявляют себя обычно в крупных системах с большим количеством исходного кода. В этой статье не будут рассматриваться большие приложения, так что нужно использовать воображение, чтобы применить принципы примера (и далеко не обязательно точный его код) в своих больших приложениях. Это не означает, что не нужно использовать паттерны в маленьких приложениях. Многие приложения начинаются как небольшие и развиваются в крупные, так что нет причин не придерживаться этих правил сразу.</p>
<p>Теперь, когда стало немного понятно, что такое паттерны проектирования, и для чего они применяются, пора переходить к пяти самым популярным паттернам проектирования PHP 5.</p>
<h3>Паттерн Factory (фабрика)</h3>
<p>Многие паттерны проектирования в оригинальной книге Design Patterns поощряют слабую связанность. Для понимания этой концепции нужно упомянуть о борьбе, через которую проходят многие разработчики крупных систем. Проблема возникает при изменении куска кода и дальнейшей попытке отследить влияние этого изменения на систему (и в худшем случае &#8211; наблюдением за каскадом отказов системы, которые, предполагалось, никак с изменённым кодом не связанными).</p>
<p>Проблема в сильной свзязанности. Функции и классы в одной части системы слишком сильно полагаются на поведение и архитектуру других функций и классов (в другой части системы). Тут нужны паттерны, которые позволят классам общаться между собой, но при этом позволят избежать слишком сильной их привязки друг к другу, что привело бы к некоторому &laquo;переплетению&raquo; кода независимых частей.</p>
<p>В больших системах большее количество завязано на нескольких ключевых классах. Проблемы могут возникнуть при изменении этих классов. Предположим, у нас есть класс User, который читает из файла. Нам нужно поменять его на другой класс, который читает из базы данных, но во всём коде идут обращения к классу, ктороый читает из файла. Здесь пригодится паттерн <strong>factory</strong>.</p>
<p>Паттерн <strong>factory</strong> &#8211; это класс, который предоставляет методы для создания объектов. Вместо использования конструкции new напрямую, для создания объектов мы используем factory-класс. Весь код, который использует этот factory-класс, меняется автоматически.<br />
В листинге1 приводится пример factory-класса. Серверная сторна состоит из двух частей: база данных и набор php-страниц для добавления каналов (фидов), запроса списка каналов и получения статьи, привязанной к определённому каналу.</p>
<blockquote><p>Листинг1. Factory1.php</p></blockquote>
<pre class="code">
&lt;?php
interface IUser
{
  function getName();
}

class User implements IUser
{
  public function __construct( $id ) { }

  public function getName()
  {
    return "Jack";
  }
}

class UserFactory
{
  public static function Create( $id )
  {
    return new User( $id );
  }
}

$uo = UserFactory::Create( 1 );
echo( $uo-&gt;getName()."\n" );
?&gt;
</pre>
<p>Интерфейс IUser определяет, что следует делать объекту user. Реализация IUser называется User, и factory-класс UserFactory создаёт объекты User (в оригинале написано IUser). На рисунке1 показана связь в виде UML.</p>
<blockquote><p>Рисунок1. Factory-класс и его интерфейс IUser и класс User</p></blockquote>
<p><img alt="" src="http://www.ibm.com/developerworks/library/os-php-designptrns/factory1.gif" class="alignnone" width="229" height="86" /><br />
Если запустить этот код в комендной строке, получим:</p>
<pre class="code">
% php factory1.php
Jack
%
</pre>
<p>В коде примера у factory запрашивается объект User и выводится результат метода getName().</p>
<p>Как вариант, паттерн factory использует factory-методы. Эти статические публичные методы класса создают объекты этого типа. Такой подход полезен, если создание объекта нетривиально. Предположим, что нам нужно сначала создать объект, а потом установить множество свойств для него. Такая версия паттерна factory инкапсулирует этот процесс, и поэтому сложный код инициализации не приходится копипастить по всему проекту. В листинге 2 показан пример использования factory-методов.</p>
<blockquote><p>Листинг2. Factory2.php</p></blockquote>
<pre class="code">
&lt;?php
interface IUser
{
  function getName();
}

class User implements IUser
{
  public static function Load( $id )
  {
        return new User( $id );
  }

  public static function Create( )
  {
        return new User( null );
  }

  public function __construct( $id ) { }

  public function getName()
  {
    return "Jack";
  }
}

$uo = User::Load( 1 );
echo( $uo-&gt;getName()."\n" );
?&gt;
</pre>
<p>Этот код гораздо проще. В нём только один интерфейс &#8211; IUser &#8211; и один класс &#8211; User &#8211; для реализации этого интерфейса. У класса User два статических метода, создающих объект (поясню: оба метода создают объект класса User, но с разными параметрами; при этом можно было бы инициализировать свойства класса по-разному в разных методах). На рисунке2 показана связь в виде UML. </p>
<blockquote><p>Рисунок2. Интерфейс IUser и класс User с двумя factory-методами</p></blockquote>
<p><img alt="" src="http://www.ibm.com/developerworks/library/os-php-designptrns/factory2.gif" class="alignnone" width="95" height="113" /><br />
 Запустив скрипт в командной строке, получим тот же результат, что и в первом примере:</p>
<pre class="code">
% php factory2.php
Jack
%
</pre>
<p>Как и было сказано, иногда использование этих паттернов похоже на стрельбу из пушки по воробьям. Тем не менее, всё равно полезно изучить конкретный код, а уж потом использовать в реальных системах.</p>
<h3>Паттерн Singleton (синглтон)</h3>
<p>Некоторые ресурсы приложения уникальны, т.е. может быть один и только один его экземпляр. К примеру, соединение с базой данных через соответствующий дескриптор уникально. Нам нужно иметь доступ к созданному дескриптору базы данных, т.к. каждый раз при запросе открывать и закрывать соединение во время загрузки страницы накладно.</p>
<p>Для этого отлично подойдёт паттерн Singleton. Объект является синглтоном, если в приложении можно обратиться к одному и только к одному такому объекту.</p>
<p>Код в листинге 3 показывает реализацию синглтона соединения с базой данных. </p>
<blockquote><p>Листинг3. Singleton.php</p></blockquote>
<pre class="code">
&lt;?php
require_once("DB.php");

class DatabaseConnection
{
  public static function get()
  {
    static $db = null;
    if ( $db == null )
      $db = new DatabaseConnection();
    return $db;
  }

  private $_handle = null;

  private function __construct()
  {
    $dsn = 'mysql://root:password@localhost/photos';
    $this-&gt;_handle =&amp; DB::Connect( $dsn, array() );
  }

  public function handle()
  {
    return $this-&gt;_handle;
  }
}

print( "Handle = ".DatabaseConnection::get()-&gt;handle()."\n" );
print( "Handle = ".DatabaseConnection::get()-&gt;handle()."\n" );
?&gt;
</pre>
<p> В коде присутствует один класс, DatabaseConnection. Нельзя создать экземпляр класса DatabaseConnection напрямую, т.к. конструктор класса закрытый. Но можно получить один и только один экземпляр класса DatabaseConnection, использую метод get. UML-диаграмма этого кода показана на рисунке 3.</p>
<blockquote><p>Рисунок 3. Синглтон соединения с базой данных</p></blockquote>
<p><img alt="" src="http://www.ibm.com/developerworks/library/os-php-designptrns/singleton.gif" class="alignnone" width="165" height="41" /><br />
Для подтверждения того, что указанным методом можно получить доступ к одному и тому же ресурсу, достаточно запустить код в командной строке.</p>
<pre class="code">
% php singleton.php
Handle = Object id #3
Handle = Object id #3
%
</pre>
<p>Оба вызова возвращают один и тот же объект. При использовании этого синглтона в приложении, одно и то же соединение будет использоваться всегда.<br />
В небольших приложениях можно обойтись глобальными переменными, но в крупных приложениях следует этого избегать путём использования объектов и методов для получения доступа к ресурсам.</p>
<h3>Паттерн Observer (наблюдатель)</h3>
<p>Паттерн Observer предлагает ещё один способ, чтобы избежать сильной связанности между компонентами. Этот паттерн простой: один объект делает себя наблюдаемым, добавляя метод, который позволяет другому объекту, наблюдателю, себя зарегистрировать.<br />
Когда наблюдаемый объект изменяется, он посылает уведомление зарегистрированным наблюдателям. Что происходит после получения уведомления с наблюдателем, не зависит от наблюдаемого объекта. В результате получаем способ общения между объектами без необходимости понимания, зачем.</p>
<p>Простой пример &#8211; список пользователей системы. Код в Листинге 4 показывает список пользователей, который отсылает уведомление при добавлении новых пользователей. За этим списком следит наблюдатель, ведущий лог; при получении уведомления он выводит сообщение.</p>
<blockquote><p>Листинг 4. Observer.php</p></blockquote>
<pre class="code">
&lt;?php
interface IObserver
{
  function onChanged( $sender, $args );
}

interface IObservable
{
  function addObserver( $observer );
}

class UserList implements IObservable
{
  private $_observers = array();

  public function addCustomer( $name )
  {
    foreach( $this-&gt;_observers as $obs )
      $obs-&gt;onChanged( $this, $name );
  }

  public function addObserver( $observer )
  {
    $this-&gt;_observers []= $observer;
  }
}

class UserListLogger implements IObserver
{
  public function onChanged( $sender, $args )
  {
    echo( "'$args' added to user list\n" );
  }
}

$ul = new UserList();
$ul-&gt;addObserver( new UserListLogger() );
$ul-&gt;addCustomer( "Jack" );
?&gt;
</pre>
<p>В коде определяются 4 элемента: 2 интерфейса и 2 класса. Интерфейс IObservable определяет наблюдаемый объект, а UserList реализует этот интерфейс, чтобы зарегистрироваться в качестве наблюдаемого. IObserver определяет, что нужно, чтобы стать наблюдателем, а UserListLogger реализует интерфейс IObserver. Это показано в виде UML на рисунке 4.</p>
<blockquote><p>Рисунок 4. Наблюдаемый UserList и наблюдатель UserListLogger</p></blockquote>
<p><img alt="" src="http://www.ibm.com/developerworks/library/os-php-designptrns/observer.gif" class="alignnone" width="414" height="99" /><br />
При запуске в командной строке получим вывод: </p>
<pre class="code">
% php observer.php
'Jack' added to user list
%
</pre>
<p>Код примера создаёт UserList и добавляет UserListLogger в качестве наблюдателя. Затем добавляется новый посетитель, и UserListLogger уведомляется об этом изменении.<br />
Важно понимать, что UserList не знает, что логгер собирается сделать. Может быть один или несколько наблюдателей, которые будут делать что-то другое. К примеру, можно сделать наблюдателя, который будет посылать некоторое сообщение новому пользователю, приветствуя вновь прибывшего.<br />
Ценность такого подхода &#8211; в том, что UserList ничего не знает об объектах, зависимых от него; он концентрируется на управлении списком пользователей и рассылает уведомления при его изменении.</p>
<p>Этот паттерн не ограничивается объектами, хранящимися в памяти. Он используется и для систем очереди сообщений на базе баз данных (database-driven message queuing systems), использующихся в крупных приложениях. </p>
<h3>Паттерн Сhain-of-command (цепочка команд)</h3>
<p>Для реализации идеи слабой связанности паттерн Сhain-of-command передаёт сообщение, команду, запрос, как угодно, через набор обработчиков. Каждый обработчик решает, сможет ли он обработать этот запрос. Если может, запрос обрабатывается и процесс передачи останавливается. Можно добавлять/удалять обработчики без влияния на другие обработчики. Листинг 5 показывает пример реализации этого паттерна.</p>
<blockquote><p>Листинг 5. Chain.php</p></blockquote>
<pre class="code">
&lt;?php
interface ICommand
{
  function onCommand( $name, $args );
}

class CommandChain
{
  private $_commands = array();

  public function addCommand( $cmd )
  {
    $this-&gt;_commands []= $cmd;
  }

  public function runCommand( $name, $args )
  {
    foreach( $this-&gt;_commands as $cmd )
    {
      if ( $cmd-&gt;onCommand( $name, $args ) )
        return;
    }
  }
}

class UserCommand implements ICommand
{
  public function onCommand( $name, $args )
  {
    if ( $name != 'addUser' ) return false;
    echo( "UserCommand handling 'addUser'\n" );
    return true;
  }
}

class MailCommand implements ICommand
{
  public function onCommand( $name, $args )
  {
    if ( $name != 'mail' ) return false;
    echo( "MailCommand handling 'mail'\n" );
    return true;
  }
}

$cc = new CommandChain();
$cc-&gt;addCommand( new UserCommand() );
$cc-&gt;addCommand( new MailCommand() );
$cc-&gt;runCommand( 'addUser', null );
$cc-&gt;runCommand( 'mail', null );
?&gt;
</pre>
<p>В коде определяется класс CommandChain, который управляет списком ICommand-объектов. Два класса реализуют интерфейс ICommand &#8211; один отвечает на запросы на почту, а другой &#8211; за добавление пользователей. UML показан на рисунке 5.</p>
<blockquote><p>Рисунок 5. Цепочка команд и соответствующие команды</p></blockquote>
<p><img alt="" src="http://www.ibm.com/developerworks/library/os-php-designptrns/chain.gif" class="alignnone" width="359" height="121" /><br />
При запуске из командной строки скрипт выведет:</p>
<pre class="code">
% php chain.php
UserCommand handling 'addUser'
MailCommand handling 'mail'
%
</pre>
<p>Код сначала создаёт объект CommandChain и добавляет в него два объекта команд. Потом запускаются две команды, чтобы посмотреть, кто на них ответит. Если имя команды не соответствует ни UserCommand, ни MailCommand, то код отрабатывает и ничего не происходит.</p>
<p>Паттерн Chain-of-command может быть ценным при создании расширяемой архитектуры обработки запросов, которая может быть применена для решения многих проблем.</p>
<h3>Паттерн Strategy (стратегия)</h3>
<p>Последним мы рассмотрим паттерн Strategy. В этом паттерне алгоритмы выносятся из сложных классов, чтобы их можно было быть легко изменить. К примеру, паттерн Strategy &#8211; это вариант, если нужно изменить способ ранжирования страниц в поисковой системе. Разобьём поисковый движок на несколько составных частей &#8211; одна пробегает по страницам, одна ранжирует каждую страницу, а ещё одна сортирует результаты, основываясь на рейтинге. Сложный путь &#8211; объединить все части в один класс. Используя паттерн Strategy, можно вынести часть, отвечающую за ранжирование страницы в другой класс, и можно будет изменять механизм ранжирования без вмешательства в остальной код поискового движка.</p>
<p>В более простом примере Листинга 6 приведён класс списка пользователей, который обеспечивает метод поиска набора пользователей, основанный на plug-and-play-наборе стратегий.</p>
<blockquote><p>Листинг 6. Strategy.php</p></blockquote>
<pre class="code">
&lt;?php
interface IStrategy
{
  function filter( $record );
}

class FindAfterStrategy implements IStrategy
{
  private $_name;

  public function __construct( $name )
  {
    $this-&gt;_name = $name;
  }

  public function filter( $record )
  {
    return strcmp( $this-&gt;_name, $record ) &lt;= 0;
  }
}

class RandomStrategy implements IStrategy
{
  public function filter( $record )
  {
    return rand( 0, 1 ) &gt;= 0.5;
  }
}

class UserList
{
  private $_list = array();

  public function __construct( $names )
  {
    if ( $names != null )
    {
      foreach( $names as $name )
      {
        $this-&gt;_list []= $name;
      }
    }
  }

  public function add( $name )
  {
    $this-&gt;_list []= $name;
  }

  public function find( $filter )
  {
    $recs = array();
    foreach( $this-&gt;_list as $user )
    {
      if ( $filter-&gt;filter( $user ) )
        $recs []= $user;
    }
    return $recs;
  }
}

$ul = new UserList( array( "Andy", "Jack", "Lori", "Megan" ) );
$f1 = $ul-&gt;find( new FindAfterStrategy( "J" ) );
print_r( $f1 );

$f2 = $ul-&gt;find( new RandomStrategy() );
print_r( $f2 );
?&gt;
</pre>
<p>UML примера представлен на рисунке 6. </p>
<blockquote><p>Рисунок 6. Список пользователей и стратегии отбора пользователей</p></blockquote>
<p><img alt="" src="http://www.ibm.com/developerworks/library/os-php-designptrns/strategy.gif" class="alignnone" width="309" height="138" /><br />
 Класс UserList представляет собой обёртку для массива имён. Он реализует метод find, который работает с одной из нескольких стратегий отбора из этих имён. Эти стратегии определены интерфейсом IStrategy, у которого есть две реализации: одна выбирает пользователей случайным образом, а в другой выбираются все имена после определённого (т.е. с учётом алфафвита).</p>
<p>При запуске в командной строке получим следующее:</p>
<pre class="code">
% php strategy.php
Array
(
    [0] =&gt; Jack
    [1] =&gt; Lori
    [2] =&gt; Megan
)
Array
(
    [0] =&gt; Andy
    [1] =&gt; Megan
)
%
</pre>
<p>В примере один и тот же список пользователей прогоняется через две стратегии и выводятся результаты. В первом случае стратегия ищет все имена, &laquo;больше&raquo;, чем &laquo;J&raquo; (Jack, Lori и Megan). Вторая стратегия выбирает имена случайным образом, и поэтому выдаёт разные результаты при разных запусках. В нашем случае это Andy и Megan.</p>
<p>Паттерн Strategy очень хорош для сложных систем управления данными, где нужна большая гибкость в фильтрации, поиске и обработке данных.</p>
<h3>Выводы</h3>
<p>Это лишь некоторые из наиболее распространённых паттернов проектирования, используемые в PHP-приложениях. Намного больше можно найти в книге Design Patterns. Не надо шарахаться от паттернов как от чего-то мистического. Паттерны &#8211; это отличные идеи, которые можно использовать при программировании на любом языке и любом уровне профессионального мастерства.</p>
<p>Перевод <a target="_blank" href="http://www.ibm.com/developerworks/library/os-php-designptrns/">статьи</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.job-blog.bullgare.ru/2009/07/%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd%d1%8b-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d1%8f-%d0%b2-php/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>

