Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. General
Code

Руководство для новичков по шаблонам проектирования

by
Length:LongLanguages:

Russian (Pусский) translation by Sergey Zhuk (you can also view the original English article)

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


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

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

Существуют три базовых типа шаблонов проектирования:

  • структурные
  • порождающие
  • поведенческие

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

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

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

Почему следует их использовать?

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

Пример

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

Довольно просто, не так ли? Теперь давайте поближе рассмотрим шаблон стратегия.


Шаблон Стратегия

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

Выше в нашем примере стратегия основывается на значении переменной $context во время инициализации класса. Если будет передано значение class_one, то будет использовать class_one и наоборот.

Довольно мило, но где я могу это использовать?

Представим, что вы разрабатываете класс, который должен как обновлять так и создавать новую запись с пользователем. Для работы ему нужны одинаковые входные данные (имя, адрес, телефон и т.д.), но в зависимости от ситуации, будут использованы разные функции для создания и обновления записи. Сейчас вы возможно просто воспользуетесь выражением if-else чтобы реализовать это, но что если потребуется использовать этот класс в другом месте? В таком случае, каждый раз придется переписывать это if-else выражение. Не проще ли будет просто передать наш контекст?

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


Шаблон адаптер.

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

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

Где я могу его использовать?

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

Сравним эти две реализации.

Подход без адаптера

Если потребуется использовать это в другом месте или просто использовать этот код в другом проекте, то нужно будет заново все перепечатать. 

Более лучший вариант

Напротив можно сделать что-то вроде этого:

В этой ситуации у нас есть класс оболочка, который будет нашим классом Account:

В таком случае вы сможете использовать класс Acount в любом месте, где это потребуется.


Шаблон фабричный метод

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

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

Где я могу это использовать?

Лучшим вариантом использования шаблона фабричный метод будет сценарий, когда у вас есть несколько вариаций одной сущности. Представим, что у нас есть класс кнопка; у класса есть различные формы, например ImageButton, InputButton и FlashButton. В зависимости от контекста, будет необходимость в разных кнопках, вот здесь и пригодится шаблон фабричный метод!

Для начала создадим наши три класса:

Затем мы можем создать наш класс фабрики:

Мы можем использовать такой код:

Выводом будет HHTML, содержащий все типы кнопок. Таким образом вы сможете указать, какую именно кнопку нужно создать в зависимости от ситуации.


Шаблон декоратор

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

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

Для реализации шаблона декоратор, выполним следующие шаги:

  1. Отнаследуем класс "Decorator" от оригинального класса "Component".
  2. В классе Decorator добавим поле-указатель на Component.
  3. Передадим объект Component в конструктор Decorator для инициализации указателя на Component.
  4. В классе Decorator перенаправляем все методы класса "Component" на указатель "Component" и 
  5. В классе Decorator переопределяем любые методы Component, чье поведение нужно изменить.

Шаги любезно предоставлены http://en.wikipedia.org/wiki/Decorator_pattern

Где я могу его использовать?

Лучшее место для использования шаблона декоратор - ситуация, когда у вас есть сущность, которой нужно добавить новый функционал, но только если этого требует конкретная ситуация. Представим, что у вас есть элемент HTML ссылка, ссылка logout, для который вы хотите реализовать разное поведение, в зависимости от текущей страницы. Для этого мы можем использовать шаблон декоратор.

Во-первых, определим какие "декорации" нам понадобятся.

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

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

Затем можно будет их использовать следующим образом:

Мы здесь видим то, как можно комбинировать несколько декораторов. Так как все декораторы используют магический метод __call, то можно вызывать оригинальные методы объекта. Если мы находимся на домашней странице и залогинены, то HTML будет выглядеть следующим образом:


Шаблон одиночка

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

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

Где я могу его использовать?

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

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


Заключение

Есть еще множество шаблонов для изучения; в этой статье я осветил лишь несколько из наиболее распространенных. Если вам интересно будет почитать про другие шаблоны проектирования, то страничка Википедии Design Patterns содержит множество полезной информации. Если этого недостаточно, то всегда можно переключиться на книгу Design Patterns: Elements of Reusable Object-Oriented Software, которая является самой лучшей книгой по шаблонам проектирования.

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

Если эта статья показалась вам полезной, обратите внимание на PHP scripts из Envato Market. Там собраны тысячи полезных скриптов, которые помогут ускорить ваш процесс разработки и достичь лучших результатов. Там вы сможете найти системы бронирования, контактные формы на основе ajax, системы новостных рассылок и многое другое.

PHP scripts on Envato Market
PHP скрипты на Envato Market
Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.