Что такое паттерн в программировании
Перейти к содержимому

Что такое паттерн в программировании

  • автор:

Паттерны в разработке — что это?

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

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

Немного истории

Сама по себе тема паттернов не является новой. Непосредственная идея по созданию принципов, описывающих решение распространенных в программировании/проектировании ПО проблем, появилась в далеком 1994 году. Именно в этом году в свет вышла известная книга «Design Patterns: Elements of Reusable Object-Oriented Software». Работа была создана целым авторским коллективом, который иногда называют «Gang of Four» (сокращенно GoF) — «Банда четырех». На деле это опытные инженеры-разработчики, вот их имена:

Паттерны в разработке — что это?

  • Ральф Джонсон,
  • Ричард Хелм,
  • Эрих Гамма,
  • Джон Влиссидес.

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

Какова польза?

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

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

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

Но у этой медали есть и другая сторона. Да, хорошая программа может подразумевать использование шаблонов проектирования. Но может и не подразумевать. А все потому, что не всегда они позволяют упрощать и улучшать программный код. То есть речь идет о том, что использовать паттерны везде и всюду, то есть применять паттерны ради самих паттернов — это явно плохая практика. Не стоит забывать, что неоправданное применение усложнит код, снизит его качество. Просто помните, что pattern ВСЕГДА должен быть оправданным — и лишь в этом случае он сможет эффективно решить проблему.

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

Паттерны в разработке — что это?

Порождающие паттерны

Порождающие паттерны абстрагируют процесс инстанцирования (процесс порождения классов и объектов). Вот их список:

  • Abstract Factory — «Абстрактная фабрика»;
  • Builder — «Строитель»;
  • Factory Method — «Фабричный метод»;
  • Prototype — «Прототип»;
  • Singleton — «Одиночка».

Структурные паттерны

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

Поведенческие паттерны

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

Паттерны в разработке — что это?

  • Chain of responsibility — «Цепочкаобязанностей»;
  • Command — «Команда»;
  • Interpreter — «Интерпретатор»;
  • Iterator — «Итератор»;
  • Mediator — «Посредник»;
  • Memento — «Хранитель»;
  • Observer — «Наблюдатель»;
  • State — «Состояние»;
  • Strategy — «Стратегия»;
  • Template method — «Шаблонный метод»;
  • Visitor — «Посетитель».

Другие классификации

В зависимости от того, относится pattern к объектам или классам, существуют и другие классификации паттернов.

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

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

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

Как сделать правильный выбор?

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

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

Вывод прост: придерживайтесь известного принципа KISS (Keep It Simple, Stupid), то есть сохраняйте программный код простым и ясным настолько, насколько это возможно. Иначе теряется весь смысл паттернов проектирования, который заключается именно в упрощении программы.

Паттерны в разработке — что это?

Хотите поработать с популярными шаблонами проектирования для Java? Желаете попробовать поработать с паттернами для C#? Обратите внимание на наши продвинутые https://otus.ru/catalog/courses?categories=programming на Java и C#:

Паттерны в разработке — что это? Паттерны в разработке — что это?

Также в Otus существует специальный курс «Архитектура и шаблоны проектирования », посвященный паттернам. Не пропустите!

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

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

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

Есть три основных типа шаблонов проектирования:

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

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

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

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

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

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

Пример

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

01 _context = $context; 09 > 10 11 public function operation1() < 12 if( $this->_context == "context_for_class_one" ) < 13 $this->_class_one->operation1_in_class_one_context(); 14 > else ( $this->_context == "context_for_class_two" ) < 15 $this->_class_two->operation1_in_class_two_context(); 16 > 17 > 18 >

Довольно просто, не так ли? Теперь посмотрим внимательнее на шаблон «Стратегия».

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

Изображение размещено с разрешения владельцев сайта cioinnervoice.wordpress.com

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

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

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

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

01 else < 09 // Это значит, что пользователь уже существует, необходимо обновить на базе данного идентификатора пользователя 10 >11 > 12 > 

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

Шаблон «Адаптер»

Изображение размещено с разрешения владельцев сайта www.uxcell.com

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

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

Как можно использовать это?

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

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

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

1 CreateOrUpdate( //inputs ); 4 5 $profile = new Profile(); 6 $profile->CreateOrUpdate( //inputs );

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

Лучше

Указанное противоположно действиям вроде приведённых ниже:

1 NewAccount( //inputs );

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

01 CreateOrUpdate( //subset of inputs ); 08 09 $profile = new Profile(); 10 $profile->CreateOrUpdate( //subset of inputs ); 11 > 12 >

Таким образом, можно использовать домен Account снова везде, где требуется, — дополнительно вы оказываетесь в состоянии обёртывать другие классы также под вашим доменным классом.

Шаблон «Фабричный метод»

Изображение размещено с разрешения владельцев сайта www.lankanewspappers.com

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

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

Когда можно использовать это?

Наилучшей ситуацией для использования шаблона «Фабричный метод» является наличие нескольких различных вариантов одного объекта. Допустим, имеется класс «кнопка»; у этого класса есть различные варианты — например, ImageButton (кнопка изображения), InputButton (кнопка ввода) и FlashButton (флэш-кнопка). В зависимости от места может потребоваться создать различные кнопки — именно здесь можно использовать «фабрику» для создания кнопок для вас!

Начнём с создания наших трёх классов:

01 _html; 08 > 09 > 10 11 class ImageButton extends Button < 12 protected $_html = ". "; //Здесь должен быть задан HTML, требуемый для вашей кнопки на базе изображения 13 >14 15 class InputButton extends Button < 16 protected $_html = ". "; //Здесь должен быть задан HTML, требуемый для вашей нормальной кнопки (); 17 > 18 19 class FlashButton extends Button < 20 protected $_html = ". "; //Здесь должен быть задан HTML, требуемый для вашей флэш-кнопки 21 >

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

01 else < 12 throw new Exception("The button type '$type' is not recognized."); 13 >14 > 15 >

Полученный код можно использовать, например, так:

1 $buttons = array('image','input','flash'); 2 foreach($buttons as $b) < 3 echo ButtonFactory::createButton($b)->getHtml() 4 >

Выходом должен быть HTML всех ваших типов кнопок. Таким образом, вы могли бы указать, какую кнопку создать в зависимости от ситуации, а также повторно использовать условие.

Шаблон «Декоратор»

Изображение размещено с разрешения владельцев сайта www.decoratorsdarlington.co.uk

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

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

Чтобы реализовать шаблон «Декоратор», можно выполнить следующие шаги:

1. Выделите оригинальный класс «Компонент» как подкласс класса «Декоратор».
2. В классе «Декоратор» добавьте указатель «Компонент» как поле.
3. Переместите «Компонент» в конструктор «Декоратора», чтобы инициализировать указатель «Компонент».
4. В классе «Декоратор» перенаправьте все методы «Компонент» на указатель «Компонент».
5. В классе «Декоратор» отмените любой метод (любые методы) «Компонент», поведение которого (которых) должно быть модифицировано.

Данные этапы размещены с разрешения владельцев сайта en.wikipedia.org/wiki/Decorator_pattern

Когда можно использовать это?

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

Сначала зададим различные требуемые «декорации»:

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

01 05 06 class LogoutLink extends HtmlLinks < 07 protected $_html; 08 09 public function __construct() < 10 $this->_html = "Logout"; 11 > 12 13 public function setHtml($html) 14 < 15 $this->_html = $html; 16 > 17 18 public function render() 19 < 20 echo $this->_html; 21 > 22 > 23 24 class LogoutLinkH2Decorator extends HtmlLinks < 25 protected $_logout_link; 26 27 public function __construct( $logout_link ) 28 < 29 $this->_logout_link = $logout_link; 30 $this->setHtml("

" . $this->_html . "

"); 31 > 32 33 public function __call( $name, $args ) 34 < 35 $this->_logout_link->$name($args[0]); 36 > 37 > 38 39 class LogoutLinkUnderlineDecorator extends HtmlLinks < 40 protected $_logout_link; 41 42 public function __construct( $logout_link ) 43 < 44 $this->_logout_link = $logout_link; 45 $this->setHtml("" . $this->_html . ""); 46 > 47 48 public function __call( $name, $args ) 49 < 50 $this->_logout_link->$name($args[0]); 51 > 52 > 53 54 class LogoutLinkStrongDecorator extends HtmlLinks < 55 protected $_logout_link; 56 57 public function __construct( $logout_link ) 58 < 59 $this->_logout_link = $logout_link; 60 $this->setHtml("" . $this->_html . ""); 61 > 62 63 public function __call( $name, $args ) 64 < 65 $this->_logout_link->$name($args[0]); 66 > 67 >

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

01 $logout_link = new LogoutLink(); 02 03 if( $is_logged_in ) < 04 $logout_link = new LogoutLinkStrongDecorator($logout_link); 05 >06 07 if( $in_home_page ) < 08 $logout_link = new LogoutLinkH2Decorator($logout_link); 09 >else < 10 $logout_link = new LogoutLinkUnderlineDecorator($logout_link); 11 >12 $logout_link->render(); 

Здесь можно видеть, как мы оказываемся в состоянии скомбинировать несколько декораторов, если это требуется. Поскольку все декораторы используют магическую функцию __call, то мы можем всё ещё вызвать методы оригинальной функции. Если принять, что мы в настоящий момент находимся внутри главной страницы и зарегистрированы, то HTML-выход должен быть следующим:

1 

Logout

Шаблон «Одиночка»

Изображение размещено с разрешения владельцев сайта intoxicologist.wordpress.com

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

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

Когда можно использовать это?

Если требуется перевести какой-либо специфический экземпляр из одного класса в другой, то можно использовать шаблон «Одиночка», чтобы устранить проведение этого экземпляра через конструктор или аргумент. Предположим, вы создали класс Session, который имитирует глобальный массив $_SESSION. Поскольку для этого класса его экземпляр требуется создать только один раз, то можно реализовать шаблон «Одиночка», как, например:

01 11 return self::$instance; 12 > 13 14 private function __construct() < >15 16 private function __clone() < >17 18 // Мы можем использовать любые другие способы сеанса 19 . 20 . 21 . 22 > 23 24 // Получить экземпляр сеанса 25 $session = Session::getInstance(); 

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

Заключение

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

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

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

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

Паттерн (шаблон)

Паттерны (шаблоны) проектирования — это способы построения программ, которые считаются хорошим тоном для разработчиков. Их еще называют шаблонами или образцами: чаще всего паттерн — это типовое решение для часто встречающейся задачи на построение.

«IT-специалист с нуля» наш лучший курс для старта в IT

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

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

Кроме паттернов, существуют антипаттерны проектирования — это плохие решения, неэффективные. Применять их считается дурным тоном.

Профессия / 8 месяцев
IT-специалист с нуля

Попробуйте 9 профессий за 2 месяца и выберите подходящую вам

vsrat_7 1 (1)

Кто пользуется паттернами проектирования

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

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

Для чего нужны паттерны

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

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

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

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

Как устроены паттерны

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

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

Отличия паттернов проектирования от архитектурных

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

Если упростить, архитектурный паттерн отвечает на вопрос «как будет устроен продукт». Например, модель MVC — архитектурный паттерн.

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

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

Курс для новичков «IT-специалист
с нуля» – разберемся, какая профессия вам подходит, и поможем вам ее освоить

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

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

  • «Фабрика» (Factory) — для создания новых объектов придумывают отдельный класс. Он создает объекты как копии некоего эталона;
  • «Прототип» (Prototype) — объект сам создает свои копии;
  • «Строитель» (Builder) — похож на фабрику, но новые объекты можно модифицировать. Они создаются по сложной логике, а не копируют эталонный;
  • «Одиночка» (Singleton) — подразумевает наличие одного большого объекта, который имеет глобальный доступ ко всему;
  • «Ленивая инициализация» (Lazy Initialization) — метод, при котором объект инициализируется не сразу, а по мере необходимости.

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

Структурные. Если порождающие паттерны отвечают за создание и взаимодействие объектов, то структурные — за то, как эти объекты структурированы в коде. Они описывают, каким образом простые классы и объекты «собираются» в более сложные.

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

Это только некоторые примеры. Реальных паттернов намного больше.

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

Примеры поведенческих паттернов:

  • «Итератор» (Iterator) — один объект последовательно дает доступ к разным другим, при этом не использует их сложные описания;
  • «Наблюдатель» (Observer) – шаблон, при котором объекты узнают об изменениях в других;
  • «Хранитель» (Memento) — помогает сохранить объект в каком-то состоянии с возможностью вернуться к нему в будущем;
  • «Цепочка ответственности» (Chain of Responsibility) — распределяет ответственность за те или иные задачи на разные объекты;
  • «Посредник» (Mediator) — организует слабые связи между объектами, чтобы снизить их зависимость друг от друга.

Как понять, какой паттерн применить

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

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

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

Преимущества паттернов проектирования

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

Недостатки паттернов проектирования

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

Стоит ли пользоваться паттернами

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

Более того: на собеседованиях уровня Middle и выше почти всегда спрашивают, знаком ли соискатель с паттернами проектирования. То есть их знание и умение ими пользоваться — практически обязательное условие для программиста уровня выше начального. И неважно, на чем вы пишете: Python, Java, JavaScript или что-нибудь еще.

Как начать работать с паттернами

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

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

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

IT-специалист с нуля

Наш лучший курс для старта в IT. За 2 месяца вы пробуете себя в девяти разных профессиях: мобильной и веб-разработке, тестировании, аналитике и даже Data Science — выберите подходящую и сразу освойте ее.

картинка (75)

Статьи по теме:
Разбор профессии и подборка востребованных специальностей

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

Что такое Паттерн?

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

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

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

Если привести аналогии, то алгоритм — это кулинарный рецепт с чёткими шагами, а паттерн — инженерный чертёж, на котором нарисовано решение, но не конкретные шаги его реализации.

Из чего состоит паттерн?

Описания паттернов обычно очень формальны и чаще всего состоят из таких пунктов:

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

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

Refactoring.Guru

  • Премиум контент
    • Книга о паттернах
    • Курс по рефакторингу
  • Рефакторинг
    • Введение в рефакторинг
      • Чистый код
      • Технический долг
      • Когда рефакторить
      • Как рефакторить
    • Каталог
    • Запахи кода
      • Раздувальщики
        • Длинный метод
        • Большой класс
        • Одержимость элементарными типами
        • Длинный список параметров
        • Группы данных
      • Нарушители объектно-ориентированного дизайна
        • Операторы switch
        • Временное поле
        • Отказ от наследства
        • Альтернативные классы с разными интерфейсами
      • Утяжелители изменений
        • Расходящиеся модификации
        • Стрельба дробью
        • Параллельные иерархии наследования
      • Замусориватели
        • Комментарии
        • Дублирование кода
        • Ленивый класс
        • Класс данных
        • Мёртвый код
        • Теоретическая общность
      • Опутыватели связями
        • Завистливые функции
        • Неуместная близость
        • Цепочка вызовов
        • Посредник
      • Остальные запахи
        • Неполнота библиотечного класса
    • Техники
      • Составление методов
        • Извлечение метода
        • Встраивание метода
        • Извлечение переменной
        • Встраивание переменной
        • Замена переменной вызовом метода
        • Расщепление переменной
        • Удаление присваиваний параметрам
        • Замена метода объектом методов
        • Замена алгоритма
      • Перемещение функций между объектами
        • Перемещение метода
        • Перемещение поля
        • Извлечение класса
        • Встраивание класса
        • Сокрытие делегирования
        • Удаление посредника
        • Введение внешнего метода
        • Введение локального расширения
      • Организация данных
        • Самоинкапсуляция поля
        • Замена простого поля объектом
        • Замена значения ссылкой
        • Замена ссылки значением
        • Замена поля-массива объектом
        • Дублирование видимых данных
        • Замена однонаправленной связи двунаправленной
        • Замена двунаправленной связи однонаправленной
        • Замена магического числа символьной константой
        • Инкапсуляция поля
        • Инкапсуляция коллекции
        • Замена кодирования типа классом
        • Замена кодирования типа подклассами
        • Замена кодирования типа состоянием/стратегией
        • Замена подкласса полями
      • Упрощение условных выражений
        • Разбиение условного оператора
        • Объединение условных операторов
        • Объединение дублирующихся фрагментов в условных операторах
        • Удаление управляющего флага
        • Замена вложенных условных операторов граничным оператором
        • Замена условного оператора полиморфизмом
        • Введение Null-объекта
        • Введение проверки утверждения
      • Упрощение вызовов методов
        • Переименование метода
        • Добавление параметра
        • Удаление параметра
        • Разделение запроса и модификатора
        • Параметризация метода
        • Замена параметра набором специализированных методов
        • Передача всего объекта
        • Замена параметра вызовом метода
        • Замена параметров объектом
        • Удаление сеттера
        • Сокрытие метода
        • Замена конструктора фабричным методом
        • Замена кода ошибки исключением
        • Замена исключения проверкой условия
      • Решение задач обобщения
        • Подъём поля
        • Подъём метода
        • Подъём тела конструктора
        • Спуск метода
        • Спуск поля
        • Извлечение подкласса
        • Извлечение суперкласса
        • Извлечение интерфейса
        • Свёртывание иерархии
        • Создание шаблонного метода
        • Замена наследования делегированием
        • Замена делегирования наследованием
  • Паттерны
    • Введение в паттерны
      • Что такое Паттерн?
      • История паттернов
      • Зачем знать паттерны?
      • Критика паттернов
      • Классификация паттернов
    • Каталог
    • Порождающие
      • Фабричный метод
      • Абстрактная фабрика
      • Строитель
      • Прототип
      • Одиночка
    • Структурные
      • Адаптер
      • Мост
      • Компоновщик
      • Декоратор
      • Фасад
      • Легковес
      • Заместитель
    • Поведенческие
      • Цепочка обязанностей
      • Команда
      • Итератор
      • Посредник
      • Снимок
      • Наблюдатель
      • Состояние
      • Стратегия
      • Шаблонный метод
      • Посетитель
    • Примеры кода
      • C#
      • C++
      • Go
      • Java
      • PHP
      • Python
      • Ruby
      • Rust
      • Swift
      • TypeScript

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *