с механизмами создания объекта и пытаются создать объекты в порядке подходящем к ситуации Структурные Структурные паттерны определяют отношения между классами и объектами позволяя им работать совместно Поведенческие Поведенческие паттерны определяют общие закономерности связей между объектами помогают упростить взаимоотношения между сущностями Следование этим паттернам уменьшает связность системы и облегчает коммуникацию между объектами что улучшает гибкость самого программного продукта в целом
ядра • Затем создает объект используя глобальные переменные и направляет его ядру • На последнем шаге происходит отправка пользователю содержательной части ответа возвращенного от ядра т е объекта 5
в последовательность а запрос передается по цепочке пока он не будет обработан каким то объектом получателем Избегая жесткой зависимости между отправителем и получателями запроса
$parsers) { $current = null; foreach ($parsers as $parser) { if (is_null($this->first)) { $this->first = $parser; } if (!is_null($current)) { $current->setNext($parser); } $current = $parser; } } public function parse(SplFileObject $file) { if ($this->first) { return $this->first->parse($file); } throw new RuntimeException( "Empty chain!"); } } Цепочка обязанностей [Chain of responsibility] Реализация цепочки обязанностей, с помощью контейнера Symfony. Вначале создаем главный класс нашей цепочки
function setNext(Parser $next) { $this->next = $next; } protected function canHandle(SplFileObject $file) { return $file->getExtension() == static::$format; } public function parse(SplFileObject $file) { if ($this->canHandle($file)) { return $this->doParse($file); } else { if (is_null($this->next)) { throw new InvalidArgumentException($file->getExtension(). " extension is not supported"); } return $this->next->parse($file); } } abstract public function doParse(SplFileObject $file); } Цепочка обязанностей [Chain of responsibility] Определим классы, которые потребуются для непосредственных обработчиков цепочки.
public function doParse(SplFileObject $file) { //parse the file } } /* ... */ class XmlParser extends Parser { public static $format = "xml"; public function doParse(SplFileObject $file) { //parse the file } } Цепочка обязанностей [Chain of responsibility] Определим несколько классов, парсеров-обработчиков.
реализованной в подклассах и которая может свести различные классы в одну функцию Если фабричному методу обеспечить надлежащий контекст то он будет в состоянии вернуть правильный объект Factory method [Фабричный метод]
createNewsletterManager() { $newsletterManager = new NewsletterManager(); return $newsletterManager ; } } /* конфиг */ services: # ... app.newsletter_manager_factory: class: AppBundle\Email\NewsletterManagerFactory app.newsletter_manager: class: AppBundle\Email\NewsletterManager factory: ['@newsletter_manager_factory', createNewsletterManager] Фабричный метод [Factory method] Наилучшей ситуацией для использования шаблона «Фабричный метод» является наличие нескольких различных вариантов одного объекта.
то применение этого паттерна переносит семейство этих алгоритмов в отдельную иерархию классов что позволяет заменять один алгоритм на другой в ходе выполнения программы и основываясь на определенном контексте при выполнении
некое место хранения • Алгоритмы сохранения должны быть взаимозаменяемыми interface ProfilerStorageInterface { public function find($ip, $url, $limit, $method, $start = null, $end = null); public function read($token); public function write(Profile $profile); public function purge(); } Symfony/Component/HttpKernel/Profiler/ProfilerStorageInterface Стратегия [Strategy] Интерфейс профайлера, определены все необходимые возможности
нужно сохранить $profile = new Profile('abcdef'); // Место хранения — файловая система $fsStorage = new FileProfilerStorage('/tmp/profiler'); $profiler = new Profiler($fsStorage); $profiler->saveProfile($profile); // Место хранения — Mysql $dbStorage = new MySQLProfilerStorage('mysql:host=localhost'); $profiler = new Profiler($dbStorage); $profiler->saveProfile($profile); Стратегия [Strategy] MySQLProfilerStorage - это некий класс, наследованный от PdoProfilerStorage
$type = null, array $options = array()); public function create($name, $type = null, array $options = array()); public function get($name); public function remove($name); public function has($name); public function all(); public function getForm(); } /* пример */ $task = new Post(); $task->setTitle("Название"); $task->setPublishedAt( new \DateTime("tomorrow")); $form = $this->createFormBuilder( $task) ->add("title", TextType::class) ->add("published_at", DateType::class) ->add("save", SubmitType:: class, array('label' => 'Добавить')) ->getForm(); Строитель [Builder] Symfony/Component/Form/FormBuilderInterface
turnPage(); public function open(); public function getPage(): int; } /* Book.php */ class Book implements BookInterface { private $page; public function open() { $this->page = 1; } public function turnPage() { $this->page++; } public function getPage(): int { return $this->page; } }
private $page = 1; private $totalPages = 100; public function pressNext() { $this->page++; } public function unlock() {} public function getPage(): array { return [$this->page, $this->totalPages]; } } /* EBookInterface.php */ interface EBookInterface { public function unlock(); public function pressNext(); public function getPage(): array; }
protected $eBook; public function __construct(EBookInterface $eBook) { $this->eBook = $eBook; } public function open() { $this->eBook->unlock(); } public function turnPage() { $this->eBook->pressNext(); } public function getPage(): int { return $this->eBook->getPage()[0]; } } EBookAdapter — приводит возможности электронной книги к обычной
format(string $text); } /* PlainTextFormatter.php */ class PlainTextFormatter implements FormatterInterface { public function format(string $text) { return $text; } } /* HtmlFormatter.php */ class HtmlFormatter implements FormatterInterface { public function format(string $text) { return sprintf('<p>%s</p>', $text); } } Например, по условиям задачи, необходимо в определенный момент, использовать определенный класс форматирования текста
$implementation; public function __construct(FormatterInterface $printer) { $this->implementation = $printer; } public function setImplementation(FormatterInterface $printer) { $this->implementation = $printer; } abstract public function get(); } Абстрактный класс, который отделен от реализации различных методов форматирования текста, но имеет внутри свойство, содержащее объект, реализующий необходимый функционал.
public function get() { return $this->implementation ->format('Hello World'); } } /* Test.php */ $service = new HelloWorldService(new PlainTextFormatter()); // $service->get() -> 'Hello World' $service->setImplementation(new HtmlFormatter()); // $service->get() -> '<p>Hello World</p>' Необходимый объект, умеющий форматировать текст, — передан “мостом” в сервис, которому необходима такая функциональность. Имплементации обоих объектов полностью отделены друг от друга.
этом весь оригинальный интерфейс объекта остается доступным Возможность безболезненного комбинирования различных декораторов в произвольном порядке навешивая их на различные объекты и в то же время иметь возможность создать оригинальный экземплярю
new Store(__DIR__. '/http_cache' ); $httpKernel = new HttpKernel($dispatcher, $resolver); $httpKernel = new HttpCache($httpKernel, $store); /* объект $httpKernel помимо имплементации возможностей HttpKernelInterface также обладает дополнительными возможностями класса HttpCache */ $httpKernel ->handle(Request:: createFromGlobals()) ->send() ; Декоратор [Decorator]
= null); public function getListeners($eventName = null); public function getListenerPriority( $eventName, $listener); public function hasListeners($eventName = null); public function addListener($eventName, $listener, $priority = 0); public function removeListener( $eventName, $listener); public function addSubscriber(EventSubscriberInterface $subscriber); public function removeSubscriber(EventSubscriberInterface $subscriber); protected function doDispatch($listeners, $eventName, Event $event); private function sortListeners( $eventName); } Посредник [Mediator] Symfony/Component/EventDispatcher/EventDispatcher
public function __construct(Order $order) { $this->order = $order; } public function getOrder() { return $this->order; } } Посредник [Mediator] Например, есть заказ, и нам необходимо будет производить какие-то действия, в определенные моменты.
new SalesListener( $mailer); $listener3 = new StockListener( $stockHandler); $dp = new EventDispatcher(); $dp->addListener( 'order.paid', [ $listener1, 'onOrderPaid' ]); $dp->addListener( 'order.paid', [ $listener2, 'onOrderPaid' ]); $dp->addListener( 'order.paid', [ $listener3, 'onOrderPaid' ], 100); $dp->dispatch('order.paid', new Event()); // Уведомляем подписчиков Посредник [Mediator] Например, есть кастомное событие, происходящее с заказом «order» , можно очень просто начать наблюдение за ними. И уведомлять всех подписчиков.
только с ним interface iTarget { public function query(); } // Другой интерфейс. Клиент с ним не умеет работать, но очень хочет interface iOther { public function request(); } /* пример */ $Target = new MyClass(); print $Target->query(); // "Other::request" # 1 // Класс, реализующий другой интерфейс class Other implements iOther { public function request() { return __CLASS__ . "::" . __METHOD__; } } class MyClass implements iTarget { protected $other = null; public function __construct() { $this->other = new Other(); } public function query() { return $this->other->request(); } }
abstract public function make(); } class iOS extends DevPol { public function make() { /* подключение доп. стилей */ } } class Android extends DevPol { public function make() { /* подключение доп. стилей */ } } class AppProc { public function __construct() { $app = App::get_device(); switch ($app->os) { case 'iOS': $obj = new iOS(); $obj->make(); break; case 'Android': $obj = new Android(); $obj->make(); break; } } }
onChanged($sender, $args); } interface MyInterface { function addLogger($logger); } class CustomerListLogger implements Logger { public function onChanged($sender, $args) { echo( "'$args' заказчик добавлен в список \n" ); } } class CustomerList implements MyInterface { private $_loggers = []; public function addCustomer( $name) { foreach($this->_loggers as $obs) { $obs->onChanged( $this, $name); } } public function addLogger($logger) { $this->_loggers[] = $logger; } } /* пример */ $cl = new CustomerList(); $cl->addLogger( new CustomerListLogger()); $cl->addCustomer( "Symfoniac");