design patterns что это

Способ качественно изучить паттерны проектирования

Привет, Хабр! Когда я изучал паттерны проектирования, я делал это с помощью прочтения двух книг: простую и понятную книгу от Head First одновременно со сложной и менее понятной книгой от Банды Четырех. Ниже описан мой опыт того, как именно я это делал, плюс выводы, впечатления и советы

Дисклеймер: я не утверждаю, что паттерны проектирования безусловно необходимы, и что если человек не прочитал паттерны Банды Четырех, то он не может называться разработчиком. Я лишь делюсь своим опытом, как изучал паттерны именно я. И надеюсь, что кому-то этот опыт окажется полезным

Итак, для изучения паттернов читал я одновременно следующие книги:

Первая книга читается легко и просто, там всё понятно; вторая книга читается сложнее, она более техническая, но там и больше полезной информации.

В чем смысл чтения двух книг одновременно: можно идти последовательно по темам (≈ паттернам), сначала читать главу из простой книги, а потом главу на ту же тему из сложной. У такого подхода есть следующие плюсы:

Более сложная информация из сложной книги усваивается качественнее за счет того, что ты уже подготовлен к потреблению этой информации

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

Соответствие глав/тем

Ниже я привел некоторый план прочтения обеих книг (объяснение, как читать этот план, находится под самим планом):

Все темы можно поделить на следующие группы:

Введения и предисловия

Паттерны, хорошо описанные в обеих книгах. Это те паттерны, которые прошли проверку временем и были доступно описаны Head First

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

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

Впечатления от книг

Head First

Специфическая обложка и кол-во страниц (600+) для такой, казалось бы, не очень серьезной книги могут оттолкнуть от прочтения, но на самом книга читается очень просто, интересно, местами даже забавно, но при этом рассказываются там вполне полезные вещи. На фоне Банды Четырех чтение этой книги воспринимается чуть ли ни как отдых.

Читать эту книгу имеет смысл последовательно, а не в случайном порядке. Именно поэтому порядок глав/тем при одновременном чтении обеих книг соответствует Head First.

Примеры кода написаны на Java.

Банда Четырех

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

Примеры кода написаны на C++ и SmallTalk. Последний язык, как мне показалось, имеет довольно специфический синтаксис, но в целом можно понять, что хотят показать авторы.

Итого

Могу предложить 4 пути:

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

Прочитать только книгу от Банды Четырех. Подходит для тех, кто уже неплохо знает паттерны и хочет изучить их глубже

Прочитать только книгу от Head First. Подходит для тех, кто хочет начать изучать паттерны, но не хочет углубляться слишком сильно

Не читать ничего. Ибо кому вообще нужны эти паттерны в реальном мире

На этом всё. Надеюсь, кому-нибудь эта статья будет полезна, и спасибо за внимание!

Источник

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

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

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

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

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

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

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

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

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

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

Пример

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

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

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


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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

Лучше

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

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

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

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


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

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

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

Читайте также:  что делать декретнице при ликвидации организации

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Заключение

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

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

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

Источник

Основы паттернов проектирования

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

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

Хотя идея паттернов как способ описания решения распространенных проблем в области проектирования появилась довольно давно, но их популярность стала расти во многом благодаря известной работе четырех авторов Эриха Гаммы, Ричарда Хелма, Ральфа Джонсона, Джона Влиссидеса, которая называлась «Design Patterns: Elements of Reusable Object-Oriented Software» (на русском языке известна как «Приемы объектно-ориентированного проектирования. Паттерны проектирования») и которая вышла в свет в 1994 году. А сам коллектив авторов нередко называют «Банда четырёх» или Gang of Four или сокращенно GoF. Данная книга по сути являлась первой масштабной попыткой описать распространенные способы проектирования программ. И со временем применение паттернов стало считаться хорошей практикой программирования.

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

Причем паттерны, как правило, не зависят от языка программирования. Их принципы применения будут аналогичны и в C#, и в Jave, и в других языках. Хотя в рамках данного руководства мы будем говорить о паттернах в контексте языка C#.

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

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

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

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

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

Абстрактная фабрика (Abstract Factory)

Фабричный метод (Factory Method)

Цепочка обязанностей (Chain of responsibility)

Шаблонный метод (Template method)

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

Паттерны классов описывают отношения между классами посредством наследования. Отношения между классами определяются на стадии компиляции. К таким паттернам относятся:

Фабричный метод (Factory Method)

Шаблонный метод (Template Method)

Источник

Шаблоны проектирования с человеческим лицом

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

Как сказано в Википедии:

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

Будьте осторожны

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

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

Порождающие шаблоны проектирования

Вкратце

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

Википедия

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

Простая фабрика

Аналогия

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

Читайте также:  что делать если лагает рокет лига

Вкратце

Простая фабрика просто генерирует экземпляр для клиента без предоставления какой-либо логики экземпляра.

Википедия

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

Пример

Для начала нам нужен интерфейс двери и его реализация.

Теперь соорудим фабрику дверей, которая создаёт и возвращает нам двери.

Когда использовать?

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

Фабричный метод

Аналогия

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

Вкратце

Это способ делегирования логики создания объектов (instantiation logic) дочерним классам.

Википедия

В классо-ориентированном программировании (class-based programming) фабричным методом называют порождающий шаблон проектирования, использующий генерирующие методы (factory method) для решения проблемы создания объектов без указания для них конкретных классов. Объекты создаются посредством вызова не конструктора, а генерирующего метода, определённого в интерфейсе и реализованного дочерними классами либо реализованного в базовом классе и, опционально, переопределённого (overridden) производными классами (derived classes).

Пример

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

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

Когда использовать?

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

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

Аналогия

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

Вкратце
Это фабрика фабрик. То есть фабрика, группирующая индивидуальные, но взаимосвязанные/взаимозависимые фабрики без указания для них конкретных классов.

Википедия

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

Пример

Создадим интерфейс Door и несколько реализаций для него.

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

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

Когда использовать?

Когда у вас есть взаимосвязи с не самой простой логикой создания (creation logic).

Строитель

Аналогия

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

Вкратце

Шаблон позволяет создавать разные свойства объекта, избегая загрязнения конструктора (constructor pollution). Это полезно, когда у объекта может быть несколько свойств. Или когда создание объекта состоит из большого количества этапов.

Википедия

Шаблон «Строитель» предназначен для поиска решения проблемы антипаттерна Telescoping constructor.

Поясню, что такое антипаттерн Telescoping constructor. Каждый из нас когда-либо сталкивался с подобным конструктором:

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

Пример

Разумная альтернатива — шаблон «Строитель». Сначала создадим бургер:

А затем добавим «строителя»:

Когда использовать?

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

Прототип

Аналогия

Помните клонированную овечку Долли? Так вот, этот шаблон проектирования как раз посвящён клонированию.

Вкратце

Объект создаётся посредством клонирования существующего объекта.

Википедия

Шаблон «Прототип» используется, когда типы создаваемых объектов определяются экземпляром-прототипом, клонированным для создания новых объектов.

То есть шаблон позволяет дублировать существующий объект и модифицировать копию в соответствии с потребностями. Без заморочек с созданием объекта с нуля и его настройкой.

Пример

В PHP это легко можно сделать с помощью clone :

Затем можно клонировать так:

Когда использовать?

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

Одиночка

Аналогия

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

Вкратце

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

Википедия

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

На самом деле шаблон «Одиночка» считается антипаттерном, не следует им слишком увлекаться. Он необязательно плох и иногда бывает полезен. Но применяйте его с осторожностью, потому что «Одиночка» вносит в приложение глобальное состояние, так что изменение в одном месте может повлиять на все остальные случаи использования, а отлаживать такое — не самое простое занятие. Другие недостатки шаблона: он делает ваш код сильно связанным (tightly coupled), а создание прототипа (mocking) «Одиночки» может быть затруднено.

Пример

Сделайте конструктор приватным, отключите расширения и создайте статическую переменную для хранения экземпляра:

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

Вкратце

Эти шаблоны в основном посвящены компоновке объектов (object composition). То есть тому, как сущности могут друг друга использовать. Ещё одно объяснение: структурные шаблоны помогают ответить на вопрос «Как построить программный компонент?»

Википедия

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

Адаптер

Аналогия

Допустим, у вас на карте памяти есть какие-то картинки. Их нужно перенести на компьютер. Нужен адаптер, совместимый с входным портом компьютера, в который можно вставить карту памяти. В данном примере адаптер — это картридер. Ещё один пример: переходник, позволяющий использовать американский блок питания с российской розеткой. Третий пример: переводчик — это адаптер, соединяющий двух людей, говорящих на разных языках.

Вкратце

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

Википедия

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

Пример

Представим себе охотника на львов.

Мост

Аналогия

Допустим, у вас есть сайт с несколькими страницами. Вы хотите позволить пользователям менять темы оформления страниц. Как бы вы поступили? Создали множественные копии каждой страницы для каждой темы или просто сделали отдельные темы и подгружали их в соответствии с настройками пользователей? Шаблон «Мост» позволяет реализовать второй подход.

Вкратце

Шаблон «Мост» — это предпочтение компоновки наследованию. Подробности реализации передаются из одной иерархии другому объекту с отдельной иерархией.

Википедия

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

Пример

Реализуем вышеописанный пример с веб-страницами. Сделаем иерархию WebPage :

Отделим иерархию тем:

Компоновщик

Аналогия

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

Вкратце

Шаблон «Компоновщик» позволяет клиентам обрабатывать отдельные объекты в едином порядке.

Википедия

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

Пример
Вот разные типы сотрудников:

А вот компания, которая состоит из сотрудников разных типов:

Декоратор

Аналогия

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

Вкратце

Шаблон «Декоратор» позволяет во время выполнения динамически изменять поведение объекта, обёртывая его в объект класса «декоратора».

Википедия

Шаблон «Декоратор» позволяет подключать к объекту дополнительное поведение (статически или динамически), не влияя на поведение других объектов того же класса. Шаблон часто используется для соблюдения принципа единственной обязанности (Single Responsibility Principle), поскольку позволяет разделить функциональность между классами для решения конкретных задач.

Пример

Возьмём в качестве примера кофе. Сначала просто реализуем интерфейс:

Можно сделать код расширяемым, чтобы при необходимости вносить модификации. Добавим «декораторы»:

Теперь приготовим кофе:

Фасад

Аналогия

Как включить компьютер? Вы скажете: «Нажать кнопку включения». Это потому, что вы используете простой интерфейс, предоставляемый компьютером наружу. А внутри него происходит очень много процессов. Простой интерфейс для сложной подсистемы — это фасад.

Вкратце

Шаблон «Фасад» предоставляет упрощённый интерфейс для сложной подсистемы.

Википедия

«Фасад» — это объект, предоставляющий упрощённый интерфейс для более крупного тела кода, например библиотеки классов.

Пример

Создадим класс computer:

Приспособленец

Аналогия

Обычно в заведениях общепита чай заваривают не отдельно для каждого клиента, а сразу в некой крупной ёмкости. Это позволяет экономить ресурсы: газ/электричество, время и т. д. Шаблон «Приспособленец» как раз посвящён общему использованию (sharing).

Читайте также:  что делать в евро трак симулятор если перевернулся

Вкратце

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

Википедия

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

Пример

Сделаем типы чая и чайника.

Заместитель

Аналогия

Открыть дверь с электронным замком можно с помощью карточки доступа (access card) или кнопки для обхода системы безопасности. То есть основная функциональность двери — открыться, а поверх неё может быть ещё какая-то функциональность — «заместитель».

Вкратце

С помощью шаблона «Заместитель» класс представляет функциональность другого класса.

Википедия

В наиболее общей форме «Заместитель» — это класс, функционирующий как интерфейс к чему-либо. Это оболочка или объект-агент, вызываемый клиентом для получения доступа к другому, «настоящему» объекту. «Заместитель» может просто переадресовывать запросы настоящему объекту, а может предоставлять дополнительную логику: кеширование данных при интенсивном выполнении операций или потреблении ресурсов настоящим объектом; проверка предварительных условий (preconditions) до вызова выполнения операций настоящим объектом.

Пример

Реализуем интерфейс двери и саму дверь:

Сделаем «заместителя», чтобы дверь могла выполнять защитную функцию:

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

Вкратце

Они связаны с присвоением обязанностей (responsibilities) объектам. От структурных шаблонов они отличаются тем, что не просто описывают структуру, но и очерчивают шаблоны передачи данных, обеспечения взаимодействия. То есть поведенческие шаблоны позволяют ответить на вопрос «Как реализовать поведение в программном компоненте?»

Википедия

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

Цепочка ответственности

Аналогия

Вкратце

Шаблон «Цепочка ответственности» позволяет создавать цепочки объектов. Запрос входит с одного конца цепочки и движется от объекта к объекту, пока не будет найден подходящий обработчик.

Википедия

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

Пример

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

Теперь с помощью определённых выше линков (Bank, Paypal, Bitcoin) подготовим цепочку:

Команда

Аналогия

Вы пришли в ресторан. Вы ( Client ) просите официанта ( Invoker ) принести блюда ( Command ). Официант перенаправляет запрос шеф-повару ( Receiver ), который знает, что и как готовить. Другой пример: вы ( Client ) включаете ( Command ) телевизор ( Receiver ) с помощью пульта ( Invoker ).

Вкратце

Шаблон «Команда» позволяет инкапсулировать действия в объекты. Ключевая идея — предоставить средства отделения клиента от получателя.

Википедия

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

Пример

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

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

Посмотрим, как всё это может использовать клиент:

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

Итератор

Аналогия

Хороший пример — радиоприёмник. Вы начинаете с какой-то радиостанции, а затем перемещаетесь по станциям вперёд/назад. То есть устройство предоставляет интерфейс для итерирования по каналам.

Вкратце

Шаблон — это способ доступа к элементам объекта без раскрытия базового представления.

Википедия

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

Пример

Теперь создадим итератор:

Посредник

Аналогия

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

Вкратце

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

Википедия

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

Пример

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

Теперь создадим «коллег»:

Хранитель

Аналогия

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

Вкратце

Шаблон «Хранитель» фиксирует и хранит текущее состояние объекта, чтобы оно легко восстанавливалось.

Википедия

Шаблон «Хранитель» позволяет восстанавливать объект в его предыдущем состоянии (отмена через откат — undo via rollback).

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

Пример

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

Сначала создадим объект «хранитель», в котором можно сохранять состояние редактора.

Теперь сделаем редактор («создатель»), который будет использовать объект «хранитель».

Наблюдатель

Аналогия

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

Вкратце

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

Википедия

В шаблоне «Наблюдатель» есть объект («субъект»), ведущий список своих «подчинённых» («наблюдателей») и автоматически уведомляющий их о любом изменении своего состояния, обычно с помощью вызова одного из их методов.

Пример

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

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

Посетитель

Аналогия

Туристы собрались в Дубай. Сначала им нужен способ попасть туда (виза). После прибытия они будут посещать любую часть города, не спрашивая разрешения, ходить где вздумается. Просто скажите им о каком-нибудь месте — и туристы могут там побывать. Шаблон «Посетитель» помогает добавлять места для посещения.

Вкратце

Шаблон «Посетитель» позволяет добавлять будущие операции для объектов без их модифицирования.

Википедия

Шаблон «Посетитель» — это способ отделения алгоритма от структуры объекта, в которой он оперирует. Результат отделения — возможность добавлять новые операции в существующие структуры объектов без их модифицирования. Это один из способов соблюдения принципа открытости/закрытости (open/closed principle).

Пример

Возьмём зоопарк: у нас есть несколько видов животных, и нам нужно послушать издаваемые ими звуки.

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

Стратегия

Аналогия

Возьмём пример с пузырьковой сортировкой. Мы её реализовали, но с ростом объёмов данных сортировка стала выполняться очень медленно. Тогда мы сделали быструю сортировку (Quick sort). Алгоритм работает быстрее на больших объёмах, но на маленьких он очень медленный. Тогда мы реализовали стратегию, при которой для маленьких объёмов данных используется пузырьковая сортировка, а для больших — быстрая.

Вкратце

Шаблон «Стратегия» позволяет переключаться между алгоритмами или стратегиями в зависимости от ситуации.

Википедия

Шаблон «Стратегия» позволяет при выполнении выбирать поведение алгоритма.

Пример

Возьмём вышеописанный пример. Сначала сделаем интерфейс стратегии и реализации самих стратегий.

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

Состояние

Аналогия

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

Вкратце

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

Википедия

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

Пример

Текстовый редактор меняет состояние текста, который вы печатаете, т. е. если выбрано полужирное начертание — то редактор печатает полужирным и т. д.

Сначала сделаем интерфейс состояний и сами состояния:

Шаблонный метод

Аналогия

Допустим, вы собрались строить дома. Этапы будут такими:

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

Вкратце

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

Википедия

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

Пример

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

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

Теперь создаём реализации:

Закругляемся

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

Источник

Сказочный портал