Шаблоны проектирования пособие для начинающих PHP

Оглавление (нажмите, чтобы открыть):

htmllab

Погружение в шаблоны проектирования даёт понимание того, как правильно применять лучшие практики для моделирования предметной области в компоненты языка программирования. Также оно (изучение) помогает разобраться почему реализованы те или иные части популярных фреймворков.

Шаблоны (иногда их называют паттернами) обычно не привязаны к языку программирования, потому что предназначены для решения типовой задачи. Узнав как создается шаблон Адаптер или Декоратор вы можете попробовать его реализовать на языке объектно-ориентированном языке программирования, который знаете. Знание базовых шаблонов также помогает разработчикам общаться в команде с коллегами — не тратиться доп. время на разъяснение концепции решения той или иной задачи.

Мы рассматриваем шаблоны проектирования в PHP на курсах PHP. В сети есть много сайтов, охватывающих эту тему. Из литературы можно посоветовать:

Шаблоны проектирования: книги

  1. PHP. Объекты, шаблоны и методики программирования. Мэтт Зандстра
  2. Паттерны проектирования. Эрик Фримен, Элизабет Фримен
  3. Приемы объектно-ориентированного проектирования. Паттерны проектирования. Эрих Гамма, Ричард Хелм и др.
  4. Шаблоны реализации корпоративных приложений. Кент Бек
  5. Применение UML 2.0 и шаблонов проектирования. Введение в объектно-ориентированный анализ, проектирование и итеративную разработку. Крэг Ларман

Книга Зандстры выдержала несколько изданий, достаточно простым языком разъясняет сложные пример (кому вначале покажется сложным, посмотрите последние две книги из списка �� ). Кроме шаблонов проектирования рассматриваются хорошие практики разработки программного обеспечения и все это применимо к PHP.

Книга Фрименов, как и все книги из серии Head&First призваны навести порядок в голове у всех начинающих, в данном случае — работать с шаблонами проектирования. Содержит очень много примеров на Java (если знаком PHP — можно читать).

На книгу Бека часто ссылается Зандстра. Но «Шаблоны реализации корпоративных приложений» лучше читать после просмотра других книг списка.

Шаблоны проектирования: фреймворки

Для того, чтобы хорошо разобраться в шаблонах, нужно знакомиться с кодом передовых разработок. Например, знакомимся с шаблоном Наблюдатель (Observer). Если параллельно рассматриваем Zend Framework 2, то обнаруживаем компонент EventManager, который реализует шаблон Наблюдатель. Это касается всех передовых фреймворков, которые на слуху.

Примечание: перед началом знакомства с шаблонами, можно посмотреть язык визуального моделирования UML. UML даёт возможность читать и создавать диаграммы, описывающие шаблоны проектирования (на самом деле, для описания взаимодействия между объектами, состояний объектов используются разные комбинации базовых фигур UML). Если есть желание создать свою UML-диаграмму не на листке бумаги, можно воспользоваться одним из онлайн-сервисов или стационарной программой. Обратите внимание на DIA она медленно, но уверенно развивается. У неё есть и неудобные моменты с точки зрения удобства использования, но она меня очень выручила, когда однажды искал способ автоматической генерации PHP-кода из диаграммы (есть плагин).

Шаблоны проектирования в PHP : 1 комментарий

Добавить комментарий Отменить ответ

Для отправки комментария вам необходимо авторизоваться.

Шаблоны

Большинство задач, с которыми часто приходится сталкиваться программистам, уже давным-давно решены другими членами нашего сообщества. Шаблоны проектирования как раз и являются тем средством, с помощью которого люди могут поделиться друг с другом накопленным опытом. Как только шаблон становится всеобщим достоянием, он обогащает наш язык и позволяет легко поделиться с другими новыми идеями проектирования и их результатами. С помощью шаблонов проектирования просто выделяют общие задачи, определяют проверенные решения и описывают вероятные результаты.

Что такое шаблоны проектирования

«В мире программного обеспечения, шаблон — это реальное проявление генетической памяти организации.»

— Гради Буч (Grady Booch), из книги Core J2EE Patterns

«Шаблон — это решение задачи в некотором контексте.»

— «Банда четырех» (The Gang of Four), из книги Design Patterns: Elements of Reusable Object-Oriented Software

Как следует из приведенных выше цитат, — это задача, взятая из практики передовых программистов, решение которой проанализировано и объяснено. Задачи имеют свойство повторяться, и веб-программистам приходится решать их снова и снова. Как обработать входящий запрос? Как преобразовать данные в команды для нашей системы? Как ввести данные? Как представить результаты? Со временем мы находим более или менее изящные ответы на эти вопросы и создаем неформальный набор методов, которые затем снова и снова используем в своих проектах. Эти методы — и есть шаблоны проектирования.

С помощью шаблонов проектирования описываются и формализуются типовые задачи и их решения. В результате опыт, который нарабатывается с большим трудом, становится доступным широкому сообществу программистов. Шаблоны должны быть построены, главным образом, по «восходящему», а не «нисходящему» принципу. Их корень — в практике, а не в теории. Но это совсем не означает, что в шаблонах проектирования отсутствует элемент теории. Шаблоны основаны на реальных методах, используемых реальными программистами. Знаменитый приверженец шаблонов Мартин Фаулер говорит, что он открывает шаблоны, а не создает их. Поэтому многие шаблоны будут вызывать у вас чувство «дежавю» — ведь вы будете узнавать методы, которые используете сами.

Каталог шаблонов — это не книга кулинарных рецептов. Рецептам можно следовать буквально, а код можно скопировать и вставить в проект с незначительными изменениями. Вам не всегда нужно даже понимать весь код, используемый в этом «рецепте». Шаблоны проектирования описывают подходы к решению конкретных задач. Детали реализации могут существенно меняться в зависимости от более широкого контекста. От этого контекста зависит выбор используемого языка программирования, природа приложения, размер проекта и специфика задачи.

Предположим, что в проекте требуется создать систему обработки шаблонов. На основании имени файла шаблона вы должны синтаксически проанализировать его содержимое и построить дерево объектов, представляющих найденные теги.

Сначала синтаксический анализатор сканирует текст на предмет поиска триггерных лексем (trigger tokens). Когда он находит соответствие, то передает лексему другому объекту-анализатору, который специализируется на чтении содержимого, расположенного внутри тегов. В результате данные шаблона продолжаются анализироваться до тех пор, пока не произойдет синтаксическая ошибка, не будет достигнут их конец, либо не будет найдена другая триггерная лексема. В случае нахождения такой лексемы, объект-анализатор также должен передать ее на обработку соответствующей программе — скорее всего, анализатору аргументов. Все вместе эти компоненты образуют то, что называется рекурсивным нисходящим синтаксическим анализатором.

Итак, вот наши участники: MainParser, TagParser и ArgumentParser. Мы также определили класс ParserFactory, который создает и возвращает эти объекты. Но, конечно, все идет не так гладко, как хотелось бы, и позже, на одном из совещаний, вы узнаете, что в шаблонах нужно поддерживать несколько синтаксисов. И теперь вам нужно создать параллельный набор объектов-анализаторов в соответствии с синтаксисом: OtherTagParser, OtherArgumentParser и т.д.

Вам поставлена такая задача: нужно генерировать различные наборы объектов в зависимости от конкретной ситуации, и эти наборы объектов должны быть более или менее «прозрачными» для других компонентов системы. Случилось так, что «Банда четырех» в своей книге определила следующую задачу для шаблона Abstract Factory (Абстрактная фабрика): «Предусмотреть интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов». Этот шаблон нам прекрасно подходит! По сути нашей задачи мы как раз должны определить и очертить рамки использования данного шаблона.

Наименование шаблона уже само по себе очень ценно; таким образом создается что-то вроде общего словаря, который годами накапливается и используется в среде профессионалов. Такие условные обозначения помогают в совместных разработках, когда оцениваются и тестируются альтернативные подходы и их различные результаты. Например, при обсуждении семейств альтернативных синтаксических анализаторов вы можете просто сказать коллегам, что система создает каждый набор с помощью шаблона Abstract Factory. Они покивают с умным видом; кто-то сразу поймет, о чем идет речь, а кто-то отметит про себя, что нужно будет узнать об этом позже. Но суть в том, что у этого набора идей и различных результатов есть абстрактный описатель, который способствует созданию более кратких обозначений. Я проиллюстрирую это чуть позже.

И наконец, согласно международному законодательству, некорректно писать о шаблонах, не процитировав Кристофера Александера (Christopher Alexander), профессора архитектуры, работы которого оказали огромное влияние на первых сторонников объектно-ориентированных шаблонов. Вот что он пишет в книге A Pattern Language (Oxford University Press, 1977):

«Каждый шаблон описывает задачу, которая возникает снова и снова, а затем описывает суть решения данной задачи, так что вы можете использовать это решение миллион раз, каждый раз делая это по-разному.»

Важно, что это определение (которое относится к архитектурным задачам и решениям) начинается с формулировки задачи и ее более широкого контекста и движется к решению. В последние годы звучала критика, что шаблонами проектирования злоупотребляют, особенно неопытные программисты. Причина в том, что решения применялись там, где не было сформулировано соответствующей задачи и контекста. Шаблоны — это несколько больше, чем конкретная организация классов и объектов, совместно работающих определенным образом. Шаблоны создаются для определения условий, в которых должны применяться решения, и для обсуждения результатов этих решений.

Обзор шаблонов проектирования

По сути, шаблон проектирования состоит из четырех частей: имени, формулировки задачи, описания решения и результатов.

Выбор имени для шаблона очень важен. Имена обогащают язык программистов; несколько коротких слов могут служить для обозначения довольно сложных задач и решений. Имена должны сочетать в себе краткость и описательность.

Формулировка задачи

Независимо от изящества решений (а некоторые из них действительно очень изящны), формулировка задачи и ее контекста — это основа шаблона. Сформулировать задачу гораздо труднее, чем применить какое-либо решение из каталога шаблонов. Это одна из причин того, что некоторые шаблоны могут применяться неправильно.

В шаблонах очень тщательно описываются условия задачи. Сначала кратко описывается сама задача, затем ее контекст; обычно приводится типичный пример и одна или несколько диаграмм. Анализируется специфика задачи, ее различные проявления. Также описываются все признаки, которые могут помочь при идентификации задачи.

Решение

Решение сначала кратко описывается вместе с задачей. Оно также описывается подробно, как правило, с использованием UML-класса и диаграмм взаимодействия. В шаблон обычно включается пример кода.

Я всегда сразу перехожу к разделу с кодом. Я считаю, что простой пример кода помогает разобраться в шаблоне. Этот пример часто сведен до минимума с целью демонстрации самой сути решения. Пример может быть написан на любом объектно-ориентированном языке, в нашем случае это PHP.

Но хотя код может присутствовать, в качестве решения никогда нельзя использовать метод «вырезать и вставить». Помните, что шаблон описывает подход к решению задачи, поскольку в реализации могут быть сотни нюансов. Представьте, что перед вами — инструкции о том, как сеять хлеб. Если вы просто слепо выполните все указания, то, скорее всего, будете голодать после сбора урожая. Гораздо полезнее подход, основанный на шаблоне, в котором описываются различные условия его применения. Основное решение задачи (заставить хлеб расти) всегда будет одним и тем же (посеять семена, поливать, собрать урожай), но реальные шаги, которые надо будет предпринять, зависят от всевозможных факторов, таких как тип почвы, местность, местные вредные насекомые и т.д.

Мартин Фаулер называет решения, описанные в шаблонах, «полусырыми», т.е. программист должен взять идею решения и закончить ее самостоятельно.

Результаты

Каждое решение по проектированию, которое вы принимаете, будет иметь широкий набор результатов. Конечно, в него должно быть включено удовлетворительное решение поставленной задачи. Решение, однажды примененное, может идеально подходить для работы с другими шаблонами. Но его нужно применять с особой осторожностью.

Зачем используются шаблоны проектирования

Так в чем преимущества шаблонов? Учитывая, что шаблон — это поставленная задача и описанное решение, ответ, казалось бы, очевиден. Шаблоны помогают решать распространенные задачи. Но, конечно, шаблон — это нечто большее.

Сколько раз вы доходили до какого-то этапа в проекте и обнаруживали, что дальше идти некуда? Вполне вероятно, вам нужно вернуться немного назад, прежде чем начать снова. Определяя распространенные задачи, шаблоны помогают улучшить проект. И иногда первый шаг к решению — это осознание того, что есть проблема.

Определив и осознав проблему (и убедившись, что это именно та проблема), с помощью шаблона вы получаете доступ к решению, а также к анализу результатов его использования. Хотя шаблон не избавляет вас от необходимости рассмотреть последствия выбранного решения, вы, по крайней мере, будете уверены, что используете проверенный метод.

В шаблонах проектирования демонстрируются и применяются принципы объектно-ориентированного проектирования. Поэтому изучение шаблонов проектирования может дать больше, чем конкретное решение в некотором контексте. В результате у вас может появиться новое видение того, как можно объединять объекты и классы для достижения поставленной цели.

PHP и шаблоны проектирования

Как я уже говорил многие шаблоны применимы ко многим языкам программирования, в которых есть возможности работы с объектами, достаточно только решить некоторые вопросы реализации (если они вообще возникают).

Но, конечно, это не всегда так. Некоторые шаблоны корпоративных приложений прекрасно используются в тех языках, где прикладной процесс продолжает свою работу между запросами к серверу. PHP работает иначе. Выполнение нового сценария начинается для каждого запроса. Это означает, что с некоторыми шаблонами нужно обращаться более аккуратно.

Например, для реализации шаблона Front Controller часто требуется довольно много времени. Хорошо, если инициализация имеет место один раз при запуске приложения, но гораздо хуже, если она происходит при каждом запросе. Это не значит, что нельзя использовать данный шаблон; я применял его в своей практике с очень хорошими результатами. Просто при обсуждении шаблона мы должны обязательно принять во внимание вопросы, связанные с PHP.

В PHP можно программировать, вообще не определяя никаких классов (хотя, учитывая продолжающееся развитие PEAR, вероятно, вы будете в некоторой степени оперировать объектами). Хотя здесь мы почти полностью концентрируемся на объектно-ориентированных решениях задач программирования, не считайте это залпом из всех орудий в войне между приверженцами разных стилей программирования. Шаблоны могут сосуществовать с другими, более традиционными, подходами. Убедительное доказательство тому — PEAR. В сборках PEAR очень изящно используются шаблоны проектирования. Они склонны быть объектно-ориентированными по своей природе. И это делает их более, а не менее, полезными в процедурных проектах. Поскольку сборки PEAR автономны и их сложность скрыта за четко описанным интерфейсом, их легко включить в проект любого типа.

Хотя шаблоны проектирования просто описывают решения задач, у них есть тенденция делать упор на решения, которые способствуют повторному использованию, гибкости и универсальности. Для достижения этого в шаблонах реализуются некоторые основные принципы объектно-ориентированного проектирования.

Композиция и наследование

— это эффективный способ описания меняющихся обстоятельств или контекста. Но за счет этого можно потерять в гибкости, особенно если на классы возложено несколько функциональных обязанностей.

Проблема

Как вы знаете, дочерние классы наследуют методы и свойства родительских классов (если они относятся к общедоступным или защищенным элементам). Мы будем использовать этот факт для создания дочерних классов, обладающих особой функциональностью.

Мастер Йода рекомендует:  Хотите быстро выучить Java Сожгите все книги

На рисунке ниже приведен простой пример с использованием UML:

Родительский класс и два дочерних

Абстрактный класс Lesson моделирует занятие в колледже. Он определяет абстрактные методы cost() и chargeType(). На диаграмме показаны два реализующих класса, FixedPriceLesson и TimedPriceLesson, которые обеспечивают разные механизмы оплаты за занятия. С помощью этой схемы наследования я могу легко изменить реализацию занятия. Клиентский код будет знать только, что он имеет дело с объектом типа Lesson, поэтому детали механизма оплаты будут прозрачными.

Но что произойдет, если нужно будет ввести новый набор специализаций? Предположим, нам нужно работать с такими элементами, как лекции и семинары. Поскольку они подразумевают разные способы регистрации учащихся и создания рабочих материалов к занятиям, для них нужны отдельные классы. Поэтому теперь у нас есть две движущие силы проекта: нам нужно работать со стратегиями оплаты и разделить лекции и семинары.

На рисунке ниже показано решение проблемы «в лоб»:

Неудачная структура наследования

Здесь показана явно неудачная иерархия. Мы не сможем в дальнейшем использовать это дерево наследования, чтобы управлять механизмами оплаты, не дублируя большие блоки функциональности. Эти стратегии оплаты повторяются в семействах классов Lecture и Seminar.

На данном этапе мы должны рассмотреть использование условных операторов в суперклассе Lesson, чтобы избавиться от дублирования. В сущности, мы удаляем логику оплаты из дерева наследования вообще, перемещая ее вверх, в суперкласс. Это полная противоположность традиционному рефакторингу, когда условные операторы заменяются полиморфизмом. Вот как выглядит исправленный класс Lesson:

А вот как я должен работать с этими классами:

Диаграмма нового класса показана на рисунке ниже:

Иерархия наследования улучшена в результате удаления расчетов стоимости занятий из подклассов

Я сделал структуру класса намного более управляемой, но дорогой ценой. Использование условных операторов в данном коде — это шаг назад. Обычно мы стараемся заменить условный оператор полиморфизмом. А здесь я сделал противоположное. Как видите, это вынудило меня продублировать условный оператор в методах chargeType() и cost(). Похоже, я обречен на дублирование кода.

Использование композиции

Для решения данной проблемы я могу воспользоваться шаблоном Strategy. Этот шаблон используется для перемещения набора алгоритмов в отдельный тип. Перемещая код для вычисления стоимости, я могу упростить тип Lesson:

Перемещение алгоритмов в отдельный тип

Я создал еще один абстрактный класс CostStrategy, в котором определены абстрактные методы cost() и chargeType(). Методу cost() нужно передать экземпляр класса Lesson, который он будет использовать для расчета стоимости занятия. Мы обеспечиваем две реализации класса CostStrategy. Объекты Lesson работают только с типом CostStrategy, а не с конкретной реализацией, поэтому мы в любое время можем добавить новые алгоритмы расчета стоимости, создавая подклассы на основе CostStrategy. При этом не понадобится вносить вообще никаких изменений в классы Lesson.

Приведем упрощенную версию нового класса Lesson:

Конструктору класса Lesson передается объект типа CostStrategy, который он сохраняет в виде свойства. Метод Lesson::cost() просто вызывает CostStrategy::cost(). Точно так же Lesson::chargeType() вызывает CostStrategy::chargeType(). Такой явный вызов метода другого объекта для выполнения запроса называется делегированием. В нашем примере объект типа CostStrategy — делегат класса Lesson. Класс Lesson снимает с себя ответственность за расчет стоимости занятия и возлагает эту задачу на реализацию класса CostStrategy. Вот как осуществляется делегирование:

Ниже приведено определение класса CostStrategy вместе с реализующими его дочерними классами:

Во время выполнения программы я легко могу изменить способ расчета стоимости занятий, выполняемый любым объектом типа Lesson, передав ему другой объект типа CostStrategy. Этот подход способствует созданию очень гибкого кода. Вместо того чтобы статично встраивать функциональность в структуры кода, я могу комбинировать объекты и менять их сочетания динамически:

В результате на выходе получим следующее:

Использование композиции при проектировании классов

Как видите, одно из следствий принятия этой структуры состоит в том, что мы рассредоточили обязанности наших классов. Объекты CostStrategy ответственны только за расчет стоимости занятия, а объекты Lesson управляют данными занятия.

Итак, композиция позволяет сделать код намного более гибким, поскольку можно комбинировать объекты и решать задачи динамически намного большим количеством способов, чем при использовании одной лишь иерархии наследования. Однако при этом могут возникнуть проблемы с читабельностью кода. В результате композиции, как правило, создается больше типов, причем с отношениями, которые не настолько предсказуемы, как в отношениях наследования. Поэтому понять отношения в такой системе немного труднее.

Разделение

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

Проблема

Повторное использование — одна из основных целей объектно-ориентированного проектирования, и тесная связь — враг этой цели. Тесная связь имеет место, когда изменение в одном компоненте системы ведет к необходимости вносить множество изменений повсюду. Вы должны стремиться создавать независимые компоненты, чтобы можно было вносить изменения, не опасаясь «эффекта домино» непредвиденных последствий. Когда вы меняете компонент, степень его независимости влияет на вероятность того, что эти изменения вызовут ошибки в других частях системы.

На второй диаграмме в этой выше мы видели пример тесной связи. Поскольку логика схем оплаты повторяется в типах Lecture и Seminar, изменения в компоненте TimedPriceLecture приведут к необходимости внесения параллельных изменений в ту же логику в компоненте TimedPriceSeminar. Обновляя один класс и не обновляя другой, я нарушаю работу системы. При этом от интерпретатора PHP я не получу никакого предупреждения. Мое первое решение, с использованием условного оператора, породило аналогичную зависимость между методами cost() и chargeType().

Применяя шаблон Strategy, я преобразовал алгоритмы оплаты в тип CostStrategy, разместил их за общим интерфейсом и реализовал каждый из них только один раз.

Тесная связь другого рода может иметь место, когда много классов в системе внедрены явным образом в платформу или среду. Предположим, вы создаете систему, которая, например, работает с базой данных MySQL. Для запросов к серверу базы данных вы можете использовать такие функции, как mysqli_connect() и mysqli_query().

Но если вам понадобится развернуть систему на сервере, который не поддерживает MySQL, вы должны будете внести изменения в весь проект, чтобы использовать, например, SQLite. При этом вы будете вынуждены вносить изменения по всему коду, и вас ожидает перспектива поддерживать две параллельные версии приложения.

И проблема здесь не в зависимости системы от внешней платформы. Такая зависимость неизбежна, поскольку мы должны работать с кодом, который связывается с базой данных. Проблема возникает, когда такой код разбросан по всему проекту. Коммуникации с базами данных — это не главная обязанность большинства классов в системе, поэтому наилучшая стратегия — выделить такой код и сгруппировать его за общим интерфейсом. Таким образом вы будете способствовать независимости классов.

В то же время, собирая код шлюза в одном месте, вы создаете условия для более легкого перехода на новую платформу, при котором не потребуется вносить изменения в остальную часть системы. Этот процесс — сокрытие реализации за ясным интерфейсом — называется инкапсуляцией.

В PEAR эта проблема решена с помощью сборки PEAR::MDB2 (который пришел на смену сборке PEAR::DB). Это обеспечивает одну точку доступа для разных систем баз данных. А недавно, благодаря встроенному расширению PDO, эта модель была включена в сам язык PHP.

В классе MDB2 существует статический метод connect(), которому передается строка, содержащая имя источника данных (DSN). В зависимости от состава этой строки, метод возвращает экземпляр объекта, реализующего класс MDB2_Driver_Common. Поэтому для строки «mysql://» метод connect() возвращает объект типа MDB2_Driver_mysql, в то время как для строки, которая начинается с «sqlite://», он возвращает объект типа MDB2_Driver_sqlite. Структура этих классов показана на рисунке:

В сборке PEAR::MDB2 клиентский код отделен от объектов базы данных

Кроме того, сборка PEAR::MDB2 позволяет отделить код приложения от специфики платформы базы данных. При условии, что вы используете совместимый SQL-код, ваше приложение будет работать со многими СУБД, включая MySQL, SQLite, MSSQL и др. При этом вам не нужно будет вносить изменения в свой код, кроме, конечно, настройки DSN. Пожалуй, это единственное место в программе, где необходимо сконфигурировать контекст базы данных. На самом деле сборка PEAR::MDB2 до некоторой степени помогает также работать и с различными «диалектами» SQL — и это одна из причин, по которой вы можете решить использовать его, несмотря на скорость и удобство PDO.

Структура, показанная на рисунке выше имеет некоторое сходство с шаблоном Abstract Factory. Более простой по своей природе, он, тем не менее, имеет такое же назначение: генерировать объект, который реализует абстрактный интерфейс и не требует от клиента непосредственного создания экземпляра объекта.

Несмотря на то что в сборке MDB2 или в расширении PDO клиентский код отделен от специфики реализации платформы СУБД, свою часть работы вы все равно должны сделать. Если ваш (теперь уже универсальный) SQL-код рассредоточен по всему проекту, вы вскоре обнаружите, что единственное изменение какого-либо аспекта проекта может повлечь за собой каскад изменений во многих местах кода. И здесь самым типичным примером было бы изменение структуры базы данных, при котором добавление дополнительного столбца в таблице может повлечь за собой изменение SQL-кода многих повторяющихся запросов к базе данных. Поэтому вам следует подумать о том, чтобы извлечь этот код и поместить его в одну сборку, тем самым отделив логику приложения от специфики реляционной базы данных.

Ослабление связи

Чтобы сделать код связи с базой данных гибким и управляемым, вы должны отделить логику приложения от специфики платформы системы управления базами данных. От такого разделения компонентов вы должны почувствовать кучу преимуществ в своих проектах.

В качестве примера представьте себе, что в нашу систему автоматизации учебного процесса нужно включить регистрационный компонент, в задачи которого входит добавление к системе новых занятий. Процедура регистрации должна предусматривать рассылку уведомлений администратору после добавления нового занятия. При этом пользователи вашей системы никак не могут решить, в каком виде эти уведомления должны рассылаться — по электронной почте или в виде текстовых сообщений. По сути, они так любят спорить, что вы вполне можете ожидать от них изменения формы коммуникаций в недалеком будущем. Более того, они могут потребовать, чтобы уведомления рассылались всеми возможными видами связи. Поэтому изменение режима уведомления в одном месте кода может повлечь за собой аналогичные изменения во многих других местах программы.

Если вы в коде будете использовать явные ссылки на класс Mailer или Texter, то тогда ваша система становится наглухо привязана к конкретному типу рассылки уведомлений. Это примерно то же самое, как привязаться к конкретному типу СУБД, используя в коде вызовы ее специализированных функций API.

Ниже приведен фрагмент кода, в котором детали реализации конкретной системы уведомления скрыты от кода, который ее использует:

Здесь я создал класс RegistrationMgr, который является простым клиентским классом для классов типа Notifier. Несмотря на то что класс Notifier абстрактный, в нем реализован статический метод getNotifier(), который создает и возвращает конкретный объект типа Notifier (TextNotifier или MailNotifier) в зависимости от сложившихся условий. В реальном проекте выбор конкретного класса типа Notifier должен определяться каким-нибудь гибким способом, например параметром в файле конфигурации. Здесь же я немного сжульничал и выбрал тип объекта случайным образом. Метод inform() классов MailNotifier и TextNotifier практически ничего не делает. Он просто выводит информацию, полученную в качестве параметра, а также дополняет ее типом сообщения, чтобы было видно, к какому классу он относится.

Обратите внимание на то, что только в методе Notifier::getNotifier() сосредоточена информация о том, какой конкретно объект типа Notifier должен быть создан. В результате я могу посылать уведомления из сотен разных участков программы, а при изменении типа уведомлений мне потребуется внести изменения только в один метод в классе Notifier.

Ниже приведен пример кода, вызывающий метод register() класса RegistrationMgr:

Вот что будет выведено в результате:

Пример использования ослабления связи между классами

На рисунке ниже приведена диаграмма классов нашего проекта:

В классе Notifier клиентский код отделен от кода реализации различных уведомителей

Обратите внимание на то, что эта структура очень сильно напоминает ту, которая используется в сборке PEAR::MDB2.

Проблемы применения шаблонов

Одна из задач, для которой не существует шаблона, заключается в необязательном или неподходящем использовании шаблонов. Такое положение вещей создало шаблонам плохую репутацию в некоторых кругах. Поскольку решения на основе шаблонов изящны и ясны, возникает искушение применять их везде, где только можно, независимо от того, есть в этом реальная необходимость или нет.

Методология экстремального программирования (extreme Programming, XP) предлагает ряд принципов, которые применимы в данной ситуации. Первый принцип: «Вам необязательно это нужно» (обычно для него используют аббревиатуру YAGNI от You aren’t going to need it). Как правило, данный принцип применяется для функций приложения, но он имеет смысл и для шаблонов.

Когда я создаю большие проекты на PHP, то обычно разбиваю приложение на уровни, отделяя логику приложения от представления данных и персистентных уровней. Я использую всевозможные виды основных и промышленных шаблонов, а также их комбинации.

Но если меня попросят создать простую форму для обратной связи небольшого веб-сайта, я могу запросто использовать процедурный код, поместив его на одну страницу с HTML-кодом. В этом случае мне не нужна гибкость в огромных масштабах, потому что я не буду что-либо строить на этой первоначальной основе. Мне не нужно использовать шаблоны, которые решают соответствующие задачи в более широких системах. Поэтому я применяю второй принцип экстремального программирования: «Сделайте самый простой работающий вариант». Работая с каталогом шаблонов, думайте о структуре и процессе решения, обращая внимание на пример кода. Но прежде чем применить шаблон, подумайте о том, «когда его использовать», найдите соответствующий раздел и прочитайте о результатах применения шаблона. В некоторых контекстах лечение может оказаться хуже болезни.

10 рекомендуемых книг-бестселлеров по PHP

�� Лучшие премиум-темы для Вордпресс от топовых разработчиков мира

Всем начинающим PHP-программистам я всегда рекомендовал и рекомендую начинать изучение языка не по обрывкам статей и записей блогеров, а с хорошего самоучителя или учебника.

Да, на блогах можно встретить много интересного и познавательного из области веб-программирования. Но матчасть все же лучше изучать по хорошим учебникам и самоучителям.

Сегодня я публикую подборку рекомендуемой учебной литературы по языку PHP. Все книги на русском языке и доступны для приобретения в Ozon.ru.

1. PHP 7

Дмитрий Котеров, Игорь Симдянов

Рассмотрены основы языка PHP и его рабочего окружения в Windows, Mac OS X и Linux.Отражены радикальные изменения в языке PHP, произошедшие с момента выхода предыдущего издания: трейты, пространство имен, анонимные функции, замыкания, элементы строгой типизации, генераторы, встроенный Web-сервер и многие другие возможности. Приведено описание синтаксиса PHP 7, а также функций для работы с массивами, файлами, СУБД MySQL, memcached, регулярными выражениями, графическими примитивами, почтой, сессиями и т. д.

Особое внимание уделено рабочему окружению: сборке PHP-FPM и Web-сервера nginx, СУБД MySQL, протоколу SSH, виртуальным машинам VirtualBox и менеджеру виртуальных машин Vagrant. Рассмотрены современные подходы к Web-разработке, система контроля версий Git, GitHub и другие бесплатные Git-хостинги, новая система распространения программных библиотек и их разработки, сборка Web-приложений менеджером Composer, стандарты PSR и другие инструменты и приемы работы современного PHP-сообщества.

В третьем издании добавлены 24 новые главы, остальные главы обновлены или переработаны.

На сайте издательства находятся исходные коды всех листингов.

2. Создаем динамические веб-сайты с помощью PHP, MySQL, JavaScript, CSS и HTML5

Робин Никсон

Новое издание признанного бестселлера, охватывающего как клиентские, так и серверные аспекты веб-разработки. Эта книга поможет вам освоить динамическое веб-программирование с применением самых современных технологий. Книга изобилует ценными практическими советами, содержит исчерпывающий теоретический материал. Для закрепления материала автор рассказывает, как создать полнофункциональный сайт, работающий по принципу социальной сети.

Мастер Йода рекомендует:  Уникальная разработка iFolder.ru предложил два варианта файлообмена в одном сервисе!

3. PHP7 для начинающих с пошаговыми инструкциями

Майк МакГрат

PHP7 — самый популярный язык программирования в мире. Новый пошаговый самоучитель поможет вам освоить азы PHP7 с нуля за короткое время. Благодаря известной методике пошагового обучения от Майка МакГрата, даже читатели, не имеющие никакого опыта в программировании, смогут приступить к созданию собственных веб-проектов.
Самоучитель написан простым языком, содержит множество иллюстраций, полезные советы и рекомендации.

4. PHP. Объекты, шаблоны и методики программирования

Мэт Зандстра

Четвертое издание книги было пересмотрено и дополнено новым материалом. Книга начинается с обзора объектно-ориентированных возможностей PHP, в который включены важные темы, такие как определение классов, наследование, инкапсуляция, рефлексия и многое другое. Этот материал закладывает основы объектно-ориентированного проектирования и программирования на PHP. Вы изучите также некоторые основополагающие принципы проектирования. В этом издании книги также описаны возможности, появившиеся в PHP версии 5.4, такие как трейты, дополнительные расширения на основе рефлексии, уточнения типов параметров методов, улучшенная обработка исключений и много других мелких расширений языка.

Следующая часть книги посвящена шаблонам проектирования, которые органически дополняют тему ООП и являются описанием элегантных решений распространенных проблем, возникающих при проектировании программного обеспечения. В ней описываются концепции шаблонов проектирования и показаны способы реализации нескольких важных шаблонов в приложениях на PHP. В этой же части приведен материал, посвященный шаблонам корпоративных приложений и баз данных.

В последней части книги описывается несколько важных утилит и методик, помогающих осуществить успешный проект на основе разрозненных кусков кода. В этой части книги описано, как управлять работой нескольких программистов с помощью Git, как выполнить построение и развертывание проекта с помощью Phing и PEAR.

Вы также изучите стратегии автоматического тестирования и построения проектов. Кроме обсуждения передовых средств построения и тестирования проектов, а также серверов непрерывной интеграции, в последней части книги описаны лучшие методики организации работы на основе системы контроля версий Git. Тем самым была отражена общая тенденция перехода на новую платформу, которая наметилась в среде разработчиков с момента выхода третьего издания книги.

Эта книга посвящена трем важным темам: основам объектов, принципам объектно-ориентированного проектирования и лучшим методикам их применения. Изучив их в комплексе читатель сможет создавать первоклассные и отказоустойчивые программные системы.

Основные темы книги:

5. PHP. Быстрый старт

Каллум Хопкинс

Все, что нужно знать о PHP в одной книге!

Язык PHP очень популярен, он обеспечивает функционирование 80% всех веб-сайтов, в том числе таких ресурсов, как Facebook, Wikipedia и WordPress. Этот язык прост в изучении и отлично подходит для начинающих. Изучение материалов нашей книги отнимет у вас минимум времени, но вы получите максимум информации, которую сразу сможете использовать!

Благодаря интенсивному курсу всего за пару дней вы можете:

  • Изучить основы PHP — синтаксис, операторы, циклы и функции;
  • Разобраться в теме объектно-ориентированного программирования;
  • Узнаете, как PHP работает с формами и данными;
  • Сможете повысить безопасность своих PHP-приложений.

Всего за несколько дней вы подготовите солидную базу для самостоятельного создания PHP-кода!

6. Современный PHP. Новые возможности и передовой опыт

Джош Локхарт

Из книги вы узнаете, как РНР превратился в зрелый полнофункциональный объектно-ориентированный язык, с пространствами имен и постоянно растущей коллекцией библиотек компонентов. Автор демонстрирует новые возможности языка на практике. Вы узнаете о передовых методах проектирования и конструирования приложений, работы с базами данных, обеспечения безопасности, тестирования, отладки и развертывания.Если вы уже знакомы с языком РНР и желаете расширить свои знания о нем, то эта книга для вас!

7. PHP. Справочник

Пол Хадсон

Книга представляет собой полное и наглядное справочное пособие по PHP. В числе многих преимуществ PHP перед другими языками web-программирования — легкость разработки и простота обращения, богатые объектно-ориентированные возможности и мощные расширения. Издание содержит емкие, но при этом понятные примеры. Оно незаменимо при создании сайтов. Начинающие php-программисты найдут здесь ответы на многие вопросы: как написать первый скрипт, подключиться к своей базе данных, динамически формировать страницы сайта. Опытным разработчикам будут весьма интересны разделы о защите информации сайта, взаимодействии с базами данных, мультимедиа, XML, а также расширенных возможностях и особенностях настройки PHP.

8. Разработка веб-приложений с помощью PHP и MySQL

Люк Веллинг, Лаура Томсон

Исчерпывающее учебное пособие по разработке веб-приложений, управляемых базами данных, с использованием PHP и MySQL! Эта книга предназначена для тех, кто знаком с основами HTML и ранее разрабатывал программы на современных языках программирования, но, возможно, не занимался программированием для Веб или не использовал реляционные базы данных.

В ней подробно описано применение последних версий PHP и MySQL для построения крупных коммерческих Web-сайтов. Основное внимание в книге уделено реальным приложениям. Здесь рассматриваются как простые интерактивные системы приема заказов, так и различные аспекты электронных систем продажи и безопасности во взаимосвязи с созданием реального Web-сайта. Подробно описаны все стадии разработки множества типовых проектов на PHP и MySQL, в числе которых служба веб-почты, приложение поддержки Web-форумов и электронный книжный магазин. Заслуживают особого внимания главы, посвященные объектно-ориентированному программированию на PHP, динамической генерации документов, доступу к веб-службам с помощью XML и SOAP и созданию приложений Web 2.0 с помощью Ajax.

Основное отличие этого издания от предыдущего состоит в том, что материалы и весь исходный код полностью переписаны для новых версий PHP 5.3 и MySQL 5.1. Книга ориентирована на профессиональных разработчиков, но будет полезной и начинающим.

PHP и MySQL представляют собой популярные технологии с открытым исходным кодом, которые практически идеально подходят для быстрой и эффективной разработки веб-приложений, управляемых базами данных. PHP — это мощный язык написания сценариев, специально созданный для того, чтобы предоставить разработчикам все возможности по быстрому построению веб-приложений. MySQL является высокопроизводительной и надежной системой управления базами данных, которая, с одной стороны, хорошо интегрируется с PHP и, с другой стороны, ориентирована на реализацию динамических Интернет-приложений.

В книге продемонстрировано, как эти два инструмента используются для создания высокоэффективных и, в то же время, интерактивных веб-приложений. Здесь представлено исчерпывающее описание языка PHP, а также рассмотрены вопросы настройки и работы с базами данных MySQL и особенности взаимодействия PHP-сценариев с базами данных и серверами.

В эту практическую, изобилующую реальными примерами книгу включено множество приложений, на основе которых демонстрируется решение общих задач: методика аутентификации посетителей на сайте; разработка полнофункциональной покупательской тележки; динамическая генерация изображений и PDF-документов; отправка и обработка электронной почты; организация дискуссионных форумов; подключение к веб-службам с использованием XML и разработка приложений Web 2.0 с интерактивностью, обеспечиваемой Ajax.

Четвертое издание книги претерпело существенные изменения — весь материал был тщательно пересмотрен и дополнен, и теперь он полностью соответствует новым версиям PHP 5.3 и MySQL 5.1.

9. PHP. Создание динамических страниц

Дэвид Пауэрс

Язык РНР сочетает мощь и простоту. Эти качества сделали его выбором №1 для миллионов разработчиков сайтов. Учитывая, что всем им приходится иметь дело с одними и теми же, по сути, задачами, авторы этой книги собрали под одной обложкой готовые решения для самых распространенных случаев: от управления файлами до работы с базами данных.

Эта книга подходит как для новичков, так и для опытных программистов РНР, поскольку здесь на практических примерах разбираются проблемы, с которыми часто сталкиваются веб-разработчики.

10. PHP и MySQL. Исчерпывающее руководство

Бретт Маклафлин

Если у вас есть опыт разработки сайтов с помощью CSS и JavaScript, то эта книга переведет вас на новый уровень — создание динамических сайтов на основе PHP и MySQL. Благодаря практическим примерам в книге вы узнаете все возможности серверного программирования. Вы прочитаете, как выстраивать базу данных, управлять контентом и обмениваться информацией с пользователями, применяя запросы и веб-формы. — Написание PHP-сценариев и создание веб-форм.

Подпишитесь на мой телеграм и первыми получайте новые материалы, в том числе которых нет на сайте.

Подпишитесь на рассылку
Один раз в месяц все новые материалы в одном письме

200 бесплатных наборов кистей для Фотошопа
387

Как в Фотошопе сменить русский язык на английский
193

25 лучших шаблонов для создания интернет-магазина на OpenCart
162

Как быстро наполнить сайт на WordPress с помощью плагина WP All Import
154

5 лучших книг по Вордпресс на русском языке
152

Как открыть *.CDR в Adobe Illustrator
146

Как быстро удалить все исходящие заявки в друзья во Вконтакте
138

Как отправить большое видео в Ватсап
133

10 рекомендуемых книг-бестселлеров по PHP
121

20 лучших шаблонов Вордпресс для сферы услуг
113

Как скачать приватное видео из фейсбука
100

Как импортировать большую базу данных MySQL в обход ограничений phpMyAdmin
98

Как использовать Media Query в JavaScript
88

Установка временнОй зоны в PHP
85

Как включить мультисайт и создать сеть сайтов на Вордпресс
85

20 лучших Вордпресс шаблонов для образовательных сайтов
65

10 бесплатных шаблонов лендингов в PSD
64

Как разрешить загрузку SVG и других форматов файлов в Вордпресс?
62

Как проверить сайт на технические ошибки онлайн
59

Подключаем цели Яндекс Метрики к WordPress Contact Form 7
58

Практикующий веб-разработчик, специализируюсь на платформе Вордпресс.

Техническая литература для веб-разработчика на PHP

Есть такое выражение: «PHP — добрая мама», которая позволяет писать код буквально, как хочешь и где хочешь, и готова простить очень многое. Если руководствоваться этой логикой, то порог входа в мир веб-разработки становится очень низким.

Трудно представить большой проект со сложной бизнес-логикой, написанный без объектно-ориентированного программирования (ООП) и на ассоциативных массивах. При разработке сложных интернет-проектов нужно обязательно иметь полноценное представление обо всех возможностях языка PHP.

Представляем пять книг, в порядке чтения от простого к сложному, которые помогут разработчику расширить свой спектр навыков, повысить профессиональный уровень и выйти на новый уровень качества — особенно при разработке сложных интернет-проектов.

«Современный PHP» – Джош Локхарт

Рекомендуемое время чтения

Коротко о главных нововведениях, которые следует знать современному веб-разработчику на php: ООП, PSR, composer, continuous integration и тд. Книга небольшая и в большей степени только указывает, что именно следует изучить более основательно.

«PHP 7» – Дмитрий Котеров, Игорь Симдянов

Рекомендуемое время чтения

Книга охватывает все ключевые вопросы по разработке на PHP 7. Детально описаны все возможности ООП в PHP 7. Подробно рассказано о современных тенденциях в мире веб-разработки (composer, PSR, git, nginx+php fpm, etc).

PHP объекты, шаблоны и методики программирования – Мэтт Зандстра

Рекомендуемое время чтения

В данной книге начинается погружение в шаблоны проектирования. Паттерн (шаблон) — непосредственно зарекомендовавший себя способ решения какой-либо задачи.

Автор подводит человека к пониманию необходимости использования шаблонов, показывает примеры решения сначала «по старинке», а потом с применением паттерна. Для лучшего понимания сути шаблона его принято представлять в виде UML диаграммы. В книге выделена отдельная глава для знакомства с UML.

Одно из главных преимуществ книги в том, то что она написана именно в контексте применения при разработке интернет-проектов на PHP.

«Паттерны проектирования» – Эрик и Элизабет Фримен

Рекомендуемое время чтения

Книга выводит способность мыслить абстракциями при проектировании системы на новый уровень.

Самое главное: программируйте на уровне интерфейсов, а не реализации. Один класс – одна задача. Слабая связность кода – залог гибкости архитектуры. Оператор new требует особого внимание, т.к. способен породить сильную связность кода. Инкапсулируйте то, что может измениться.

«Приемы объектно-ориентированного проектирования» – Э. Гамма, Р. Хелм, Р. Джонсон, Д. Влиссидес

Рекомендуемое время чтения

Книга содержит обширный список наиболее популярных паттернов от «Банды четырех», которые были первооткрывателями в направлении стандартизации и классификации паттернов.

Каждый шаблон содержит общее описание, типовую задачу, в контексте которой его можно применять, диаграмму классов, примеры кода, и аргументы «за» и «против» использования шаблона.

DesignPatternsPHP¶

Это набор известных шаблонов проектирования (паттернов) и некоторые примеры их реализации в PHP. Каждый паттерн содержит небольшой перечень примеров.

Я считаю, проблема паттернов в том, что люди часто знакомы с ними, но не представляют как их применять.

Паттерны¶

Паттерны могут быть условно сгруппированы в три различные категории. Нажмите на заголовок каждой страницы с паттерном для детального объяснения паттерна в Википедии.

© Copyright 2011-2020, Dominik Liebler and contributors Revision 04acce67 .

Шаблоны проектирования в PHP

Сейчас мы поговорим о шаблонах проектирования, а если точнее, то о шаблонах проектирования интернет-приложений на PHP. Профессиональные разработчики вряд ли узнают что-то новое, но для новичков данная статья будет очень полезна.

Что такое шаблоны проектирования?

Это вовсе не аналитические шаблоны, не описание стандартных структур информации вроде связных перечней. Также это не правила, по которым строятся определенные интерфейсы и приложения.

Шаблоны проектирование — это:

  • фактически является «описанием взаимодействия классов и объектов, построенным для решения типичных задач проектирования в конкретном контексте». Иными словами, шаблоны проектирования предоставляют весь набор подходов к решению различных каждодневных проблем.
  • не класс или библиотека, которые можно бы было просто включить в имеющуюся систему, это не определенный алгоритм, который можно бы было преобразовать в код.
  • что-то большее, они описывают способы, посредством которых может быть спроектирована любая программная система, которая решает проблему конкретного рода.
  • значительно ускоряют разработку приложений, так как собой представляют проверенные практикой решения, которые нужно лишь воплотить в определенной архитектуре. Кроме того, шаблоны проектирования очень упрощают понимание достаточно сложных концепций.

Разумеется, следует в выборе шаблона проектирования для решения каждой определенной проблемы проявлять осмотрительность.

«Каждый из шаблонов описывает одну из тех проблем, возникающих раз за разом. И потом описывает основу решения данной проблемы так, что вы можете воплотить такое решение во множестве программ, при этом ни разу не повторившись.», К. Александер.

Виды шаблонов проектирования

В настоящее время существует 23 шаблона проектирования, в соответствии с их назначением они разделены на три группы:

  1. порождающие шаблоны: применяются для создания объектов, которые потом могут использоваться независимо от системы, создавшей их:
    • Абстрактная фабрика (имена производимых объектов).
    • Строитель (соотношение элементов сложных объектов).
    • Фабричный метод (подкласс создаваемых объектов).
    • Прототип (класс создаваемых объектов).
    • Одиночка (класс имеет единственную инстанцию).
  2. структурные шаблоны: объединяют в одну логическую структуру объекты, несвязанные друг с другом:
    • Адаптер (интерфейс к объекту).
    • Мост (реализация объекта).
    • Компоновщик (структура и соотношение элементов объекта).
    • Декоратор (ответственность объекта такого же класса).
    • Фасад (интерфейс к подсистеме объекта).
    • Приспособленец (подсистема хранения объекта).
    • Заместитель (способ и место обращения к объекту).
  3. поведенческие шаблоны: управляют отношениями, алгоритмами и распределением обязанностей между различными программными объектами:
  4. Посетитель (операции, которые осуществляются с объектом, без изменения его класса).
  5. Хранитель (какие частные данные класса хранятся вне его, и когда).
  6. Шаблонный метод (последовательность действий).
  7. Стратегия (выбор алгоритма).
  8. Состояние (состояние объектов).
  9. Наблюдатель (число зависимых объектов и метод обновления их состояния).
  10. Посредник (порядок и доступ взаимодействия объектов друг с другом).
  11. Интератор (порядок доступа к вложенным частям).
  12. Цепочка ответственности (выбор объекта, который способен выполнить этот запрос).
  13. Команда (способ и время выполнения запроса).

Основные шаблоны проектирования в php

А теперь мы расскажем вам подробнее о наиболее востребованных из вышеперечисленных шаблонов.

В определенном случае может потребоваться обеспечить доступ к паре одиночек в одном проекте.

Реализуя этот шаблон, вы инкапсулируете какую-то группу алгоритмов таким образом, чтобы порожденный класс мог воспользоваться ими, при этом ничего не зная об их конкретной реализации.

Данный шаблон подразумевает внедрение совсем нового поведения в объект в момент выполнения программы.

Это еще один очень популярный шаблон. Он производит инстанции объектов.

Иными словами, представьте ситуацию, что у вас есть реальная фабрика, которая производит какое-то изделие. Мы можем не иметь понятия, как фабрика производит данное изделие, но у нас есть универсальный метод его заказать.

Мастер Йода рекомендует:  Увидела свет новая тестовая версия Internet Explorer 9 от Microsoft

Бывает так, что когда у нас есть несколько похожих фабрик, и нам необходимо скрыть всю логику выбора фабрики для каждого определенного запроса. Здесь нам поможет именно этот шаблон.

«Наблюдатель» – шаблон, который предусматривает для наблюдаемого объекта полную возможность зарегистрировать наблюдателя, когда тот вызовет особый метод.

Затем, если состояние наблюдаемого объекта будет меняться, он посылает об этом сообщение своим наблюдателям.

«Адаптер» позволяет надстроить интерфейс над классом, чтобы применять его в системе, которая использует другие соглашения вызова.

Представьте себе ситуацию: при создании инстанции объекта вы пока не знаете, какие из функций потребуются объекту в будущем, а какие из них – нет.

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

В основе этого шаблона – серия обработчиков событий, которые передают сообщения по цепочке.

Когда сообщение проходит по цепочке, то каждый обработчик определяет самостоятельно, должен ли он как-то реагировать на сообщение, а если да, то как именно. Процесс останавливается, в случае если обработчик знает, как именно обработать событие.

«Пул объектов» – еще одна хэш-таблица. Все объекты в нее помещаются сразу после инициализации и затем извлекаются по мере потребности.

Иногда инициализация определенных объектов может проходить в несколько этапов. Было бы разумно сэкономить ресурсы на первом этапе.

Для этого создается «прототип» – заранее инициализированный и сохраненный объект, который потом может быть клонирован и полностью инициализирован.

Мы можем применять данный шаблон для того, чтобы упростить образование сложного объекта.

Урок 17. Курс по ООП PHP. Шаблоны проектирования

Дата публикации: 01-06-2020

От автора: продолжаем изучение объектно-ориентированного программирования (ООП) в PHP. При разработке веб-приложений часто приходится решать одни и те же задачи. Для многих из них были найдены универсальные решения, которые и принято называть шаблонами проектирования. Использование шаблонов проектирования в PHP может существенно сэкономить время, помочь выработать общую стратегию построения веб-приложений и упростит процесс создания документации для ваших скриптов. В этом уроке мы с вами рассмотрим тему шаблонов проектирования и познакомимся с одним из них.

Шаблоны проектирования: пособие для начинающих PHP

Что же такое шаблоны проектирования? Шаблоны проектирования это не шаблоны анализа, это не описания стандартных структур (например, связанных списков). Это не определенные разработки приложений или фреймворков. По сути, шаблоны проектирования это «описания взаимодействующих объектов и классов, предназначенных для решения общей проблемы проектирования в определенном контексте». Иным словами, шаблоны проектирования предоставляют обобщенное, многократно применяемое решение проблем программирования, с которыми мы сталкиваемся каждый день. Шаблоны проектирования это не готовые классы или библиотеки, которые можно просто применить к вашей системе. Это не конкретное решение, которое можно преобразовать в исходный код. Шаблоны проектирования – это намного больше. Это шаблоны, которые можно использовать для решения проблемы в различных конкретных ситуациях.

Шаблоны проектирования помогают ускорить разработку, потому что они уже проверены временем, и со стороны разработчика требуется лишь их выполнить. Шаблоны проектирования не только ускоряют процесс разработки программного обеспечения, но и представляют сложные понятия в более простой форме. Однако нужно быть острожным и не использовать шаблоны проектирования там, где это не нужно. Помимо теории, мы также приведем наиболее абстрактные и простые примеры шаблонов проектирования.

«Каждый шаблон описывает проблему, которая возникает снова и снова … а затем описывает суть решения этой проблемы, причем таким образом, что вы можете применять это решение миллионы раз, ни разу не повторившись.” – Кристофер Александр

На данный момент существует 23 шаблона проектирования, которые по их назначению можно разделить на три категории:

  • Порождающие шаблоны: используются для создания объектов, которые можно отделять от их системы реализации
  • Структурные шаблоны: используются для формирования больших объектных структур между множеством разрозненных объектов
  • Поведенческие шаблоны: используются для управления алгоритмами, отношениями и обязанностями между объектами

Ниже приведен полный список шаблонов проектирования:

Порождающие шаблоны

  • Abstract Factory (Абстрактная фабрика) — позволяет создавать целые группы взаимосвязанных объектов, которые, будучи созданными одной фабрикой, реализуют общее поведение.
  • Builder (Строитель) — используется для отделения процесса конструирования сложного объекта от его представления, так что в результате одного и того же конструирования могут получаться различные объекты. Этот паттерн очень похож на абстрактную фабрику, но в нем акцентируется пошаговое конструирование объекта — в отличие от фабрики, где конструируется семейство классов.
  • Factory Method (Фабричный метод) — предоставляет подклассам интерфейс для создания экземпляров некоторого класса.
  • Prototype (Прототип) — используется для задания вида создаваемых объектов на основе объекта прототипа, от которого происходит передача внутреннего состояния (создаёт новые объекты путём копирования прототипа).

Структурные шаблоны

  • Adapter (Адаптер) — предназначен для организации использования функций объекта, недоступного для модификации, через специально созданный интерфейс.
  • Bridge (Мост) — используется для отделения абстракции от ее реализации так, чтобы и то и другое можно было изменять независимо.
  • Composite (Компоновщик) — используется для компоновки объектов в древовидные структуры для представления иерархий, позволяя одинаково трактовать индивидуальные и составные объекты.
  • Decorator (Декоратор) — используется для динамического расширения функциональности объекта. Является гибкой альтернативой наследованию.
  • Facade (Фасад) — представляет собой унифицированный интерфейс вместо набора интерфейсов некоторой подсистемы. Паттерн фасад определяет интерфейс более высокого уровня, который упрощает использование подсистем.
  • Flyweight (Приспособленец) — используется для уменьшения затрат при работе с большим количеством мелких объектов.
  • Proxy (Прокси) — который предоставляет объект, который контролирует доступ к другому объекту, перехватывая все вызовы (выполняет функцию контейнера).

Поведенческие шаблоны

  • Chain of responsibility (Цепочка обязанностей) — служит для ослабления связи между отправителем и получателем запроса. При этом сам по себе запрос может быть произвольным.
  • Command (Команда) — представляет собой действие. Объект команды заключает в себе само действие и его параметры.
  • Interpreter (Интерпретатор) — решает часто встречающуюся, но подверженную изменениям, задачу.
  • Iterator (Итератор) — представляет собой объект, позволяющий получить последовательный доступ к элементам объекта-агрегата без использования описаний каждого из агрегированных объектов.
  • Mediator (Медиатор) — обеспечивает взаимодействие множества объектов, формируя при этом слабую связанность и избавляя объекты от необходимости явно ссылаться друг на друга.
  • Memento (Хранитель) — позволяет, не нарушая инкапсуляцию, зафиксировать и сохранить внутреннее состояние объекта так, чтобы позднее восстановить его в это состояние.
  • Observer (Наблюдатель) — создает механизм у класса, который позволяет получать экземпляру объекта этого класса оповещения от других объектов об изменении их состояния, тем самым наблюдая за ними.
  • State (Состояние) — используется в тех случаях, когда во время выполнения программы объект должен менять свое поведение в зависимости от своего состояния.
  • Strategy (Стратегия) — предназначен для определения семейства алгоритмов, инкапсуляции каждого из них и обеспечения их взаимозаменяемости. Это позволяет выбирать алгоритм путем определения соответствующего класса. Шаблон Strategy позволяет менять выбранный алгоритм независимо от объектов-клиентов, которые его используют.
  • Template Method (Шаблонный метод) — определяет основу алгоритма и позволяет наследникам переопределять некоторые шаги алгоритма, не изменяя его структуру в целом.
  • Visitor (Посетитель) — описывает операцию, которая должна быть выполнена над каждым объектом из некоторой произвольной структуры.

Теперь рассмотрим некоторые из этих шаблонов. Посмотреть все паттерны с примерами и объяснениями на русском вы также сможете по ссылке https://designpatternsphp.readthedocs.org/ru/latest/

Стратегия

Этот шаблон основан на алгоритмах. Вы инкапсулируете определенные виды алгоритмов, не позволяя классу клиента, ответственного за инстанциирование определенного алгоритма, узнать о фактической реализации. Пример:

Декоратор

Этот шаблон позволят добавлять новое или дополнительное поведение объекту во время выполнения, в зависимости от ситуации. Пример:

Реестр

Этот шаблон немного выделяется из общего списка, потому что он не является Порождающим шаблоном. Реестр это хэш, получить доступ к данным которого можно при помощи статических методов:

Фабрика

Это еще один очень популярный шаблон. Его название говорит само за себя: это класс, который подобен настоящей фабрике экземпляров объекта. Иными словами, предположим, что мы знаем, что существуют фабрики, производящие определенный тип продукта. Нам не важно, как фабрика производит этот продукт, но мы знаем, что для каждой фабрики есть один универсальный способ запросить этот продукт:

Абстрактная фабрика

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

Наблюдатель

За объектом устанавливается наблюдение путем добавления метода, который позволяет зарегистрироваться другому объекту (наблюдателю). Если наблюдаемый объект изменяется, он посылает сообщение объектам, которые были зарегистрированы в качестве наблюдателей:

Адаптер

Этот шаблон позволяет вам создавать класс с новым интерфейсом, с тем, чтобы этот класс мог использоваться системой с определенными методами вызова:

Отложенная инициализация

Вот еще одна интересная ситуация. Представьте, что у вас есть фабрика, но вы не знаете, какие из ее функций вам нужны, а какие – нет. В таком случае необходимые операции выполняются только если они необходимы и только один раз:

Цепочка команд

Этот шаблон также известен под названием Chain of Command. Это цепочка команд с рядом обработчиков. Сообщение (запрос) проходит через ряд этих обработчиков, и на каждом этапе принимается решение о том, может ли данный обработчик обработать запрос или нет. Процесс останавливается тогда, когда выясняется, что обработчик может обработать запрос:

Пул объектов

Пул объектов это хэш, в который можно помещать инициализированные объекты и, при необходимости, доставать их оттуда:

Прототип

Иногда некоторые объекты следует инициализировать более одного раза. Поэтому следует сохранить их инициализацию, особенно если она требует много времени и ресурсов. Прототип это заранее инициализированный и сохраненный объект. При необходимости, его можно клонировать:

Строитель

Этот шаблон используется, если мы хотим инкапсулировать создание сложного объекта:

Шаблоны Проектирования

Вопрос в правильности использования Шаблонов и построении класса.

В моделе фабрики содержатся методы по созданию функциональных объектов:

  • UploadControl — Загрузка файлов
  • FileControl — Операции над файлами
  • DataBase — Операции с базой данных

И методы для ведения лога внутри этих объектов

  • UseObserver — Использование стандартного наблюдателя
  • AddObserver — Добавление нового наблюдателя
  • RemoveObserver — Удаление наблюдателя
  • GetObserver получение наблюдателя

Суть вопроса: Правильно ли я использую Шаблон фабрики и Наблюдателя? Как сделать лучше? Смогу ли я после выполнения функции следующего вида:

Получить из наблюдателя лог ошибок и проделанной работы в функции?

Ниже код фабрики:

2 ответа 2

При проектировании какой либо системы, помимо комбинирования шаблонов проектирования вы должны руководствоваться принципами SOLID. Если этого не сделать, то хорошее приложение вам создать не удастся.

Давайте попробуем привести ваш код к человеческому виду, используя эти принципы.

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

Далее, вам стоит задуматься о передаче всех зависимостей классу в явном виде. Например, вы создаете объект базы данных в некоторой фабрике объектов.

Очевидно, что это вовсе не задача фабрики. Весь смысл жизни фабрики должен сводится к созданию продуктов. Все остальное следует вынести куда-то еще.

Далее, вам стоит сократить API для подключения наблюдателей. Хорошим вариантом может быть интерфейс SplSubject , либо производной от него. От метода UseObserver стоит отказаться.

В классической реализации Наблюдателя, субъекту передается только наблюдатель, без имени. На самом деле, имя является избыточным, поскольку все наблюдатели должны реализовывать один и тот же интерфейс, и субъект не должен знать о деталях их реализации.

Теперь поговорим собственно о логировании. В ряде случаев, экземпляр логера передается объектам в явном виде. Так происходит, например, в Symfony. Я бы рекомендовал вам использовать логер напрямую, вместо заворачивания его в один из наблюдателей. Да, это создаст еще одну явную зависимость у класса, но позволит не реализовывать лишний раз шаблон «Наблюдатель». Кроме того, это позволит упростить ваш код. Если вдруг класс UploadControl создает еще какую-то сущность и этой сущности нужен функционал логирования, то у вас начнутся проблемы. UploadControl ничего не знает о логере. Все что он может — передать наблюдатель, связанный с логированием. Это мягко говоря костыль. Поэтому, вам на самом деле не нужен шаблон Наблюдатель в данном конкретном случае. Совсем.

Кстати, существует даже унифицированный интерфейс для логгера, определенный в PSR-3.

Ну и небольшое замечание от перфекциониста напоследок: вам стоит унифицировать имена используемых методов. Если вы используете GetObserver , то и вместо Module стоит использовать getModule . Это упростит жизнь тому, кто будет поддерживать ваш код. Ну и UseObservet (обратите внимание на t на конце) это вообще жесть.

А еще стоит обратить внимание на популярный стиль именования, описанный в PSR-1 и PSR-2.

Итак, как может выглядеть код, с учетом замечаний выше:

Шаблоны Проектирования

Вопрос в правильности использования Шаблонов и построении класса.

В моделе фабрики содержатся методы по созданию функциональных объектов:

  • UploadControl — Загрузка файлов
  • FileControl — Операции над файлами
  • DataBase — Операции с базой данных

И методы для ведения лога внутри этих объектов

  • UseObserver — Использование стандартного наблюдателя
  • AddObserver — Добавление нового наблюдателя
  • RemoveObserver — Удаление наблюдателя
  • GetObserver получение наблюдателя

Суть вопроса: Правильно ли я использую Шаблон фабрики и Наблюдателя? Как сделать лучше? Смогу ли я после выполнения функции следующего вида:

Получить из наблюдателя лог ошибок и проделанной работы в функции?

Ниже код фабрики:

2 ответа 2

При проектировании какой либо системы, помимо комбинирования шаблонов проектирования вы должны руководствоваться принципами SOLID. Если этого не сделать, то хорошее приложение вам создать не удастся.

Давайте попробуем привести ваш код к человеческому виду, используя эти принципы.

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

Далее, вам стоит задуматься о передаче всех зависимостей классу в явном виде. Например, вы создаете объект базы данных в некоторой фабрике объектов.

Очевидно, что это вовсе не задача фабрики. Весь смысл жизни фабрики должен сводится к созданию продуктов. Все остальное следует вынести куда-то еще.

Далее, вам стоит сократить API для подключения наблюдателей. Хорошим вариантом может быть интерфейс SplSubject , либо производной от него. От метода UseObserver стоит отказаться.

В классической реализации Наблюдателя, субъекту передается только наблюдатель, без имени. На самом деле, имя является избыточным, поскольку все наблюдатели должны реализовывать один и тот же интерфейс, и субъект не должен знать о деталях их реализации.

Теперь поговорим собственно о логировании. В ряде случаев, экземпляр логера передается объектам в явном виде. Так происходит, например, в Symfony. Я бы рекомендовал вам использовать логер напрямую, вместо заворачивания его в один из наблюдателей. Да, это создаст еще одну явную зависимость у класса, но позволит не реализовывать лишний раз шаблон «Наблюдатель». Кроме того, это позволит упростить ваш код. Если вдруг класс UploadControl создает еще какую-то сущность и этой сущности нужен функционал логирования, то у вас начнутся проблемы. UploadControl ничего не знает о логере. Все что он может — передать наблюдатель, связанный с логированием. Это мягко говоря костыль. Поэтому, вам на самом деле не нужен шаблон Наблюдатель в данном конкретном случае. Совсем.

Кстати, существует даже унифицированный интерфейс для логгера, определенный в PSR-3.

Ну и небольшое замечание от перфекциониста напоследок: вам стоит унифицировать имена используемых методов. Если вы используете GetObserver , то и вместо Module стоит использовать getModule . Это упростит жизнь тому, кто будет поддерживать ваш код. Ну и UseObservet (обратите внимание на t на конце) это вообще жесть.

А еще стоит обратить внимание на популярный стиль именования, описанный в PSR-1 и PSR-2.

Итак, как может выглядеть код, с учетом замечаний выше:

Добавить комментарий