Понятие шаблона пришло из работ архитектора Кристофера Александра (Christopher Alexander), написанных в конце 1970-х годов. В своих книгах он использовал понятие шаблона для описания вопросов планирования городов и проектирования архитектуры зданий.
В конце 1980-х идею шаблонов начали применять при разработке программного обеспечения. С тех пор были выделены различные виды шаблонов, разработаны языки шаблонов и созданы многочисленные библиотеки, содержащие шаблоны для самых разных областей информационных технологий.
Шаблоны упрощают повторное использование удачных проектных, архитектурных, аналитических и других решений. Представление проверенных временем методик в виде шаблонов облегчает доступ к ним со стороны разработчиков новых систем. С помощью шаблонов можно улучшить качество документации, кода и других артефактов, создаваемых при разработке систем. Шаблоны могут быть полезны для улучшения процесса разработки. Шаблоны описывают причины, почему система должна быть построена так, а не иначе.
Шаблон программы
Существует несколько десятков определений шаблонов. Большинство из них отмечает, что шаблон является описанием удачного варианта решения определенной повторяющейся задачи в конкретном контексте. Приведем несколько определений шаблонов.
Шаблон (по Кристоферу Александру) — правило из трех частей, выражающее связи между определенным контекстом, задачей и решением. Как часть мира, шаблон связывает контекст , систему сил, регулярно появляющуюся в этом контексте, и определенную пространственную конфигурацию, позволяющую системе сил прийти в равновесие. Как элемент языка шаблон является инструкцией, описывающей повторное использование этой пространственной конфигурации для приведения системы сил в равновесие, когда это позволяет контекст . Шаблон — нечто, происходящее в реальном мире, и одновременно правило, описывающее, как и когда создавать это нечто. Это процесс и вещь, описание живой сущности и процесса, порождающего эту сущность.
Классические книги по ИТ-шаблонам описывают шаблон как нечто, состоящее из четырех основных элементов:
- Имя. Сославшись на имя, можно сразу описать проблему, ее решения и последствия. Присваивание шаблонам имен позволяет проектировать на более высоком уровне абстракции. С помощью словаря шаблонов можно вести обсуждение с коллегами, упоминать шаблоны в документации, представлять тонкости системы.
- Задача. Описание того, когда следует применять шаблон. Формулируется задача и ее контекст. (Примером конкретной задачи может служить способ представления алгоритмов в виде объектов). Иногда в описание задачи входит перечень условий, при выполнении которых имеет смысл применять шаблон.
- Решение. Описание элементов решения (элементов проектирования, анализа, тестирования и др. — в зависимости от вида шаблона), отношений между ними, функций каждого элемента. При этом решение — не конкретный дизайн или реализация, так как шаблон применяется в самых разных контекстах. Просто дается абстрактное описание задачи и того, как она может быть решена с помощью некоего весьма общего сочетания элементов (в случае проектирования, например, это могут быть объекты и классы).
- Результаты. Результаты — это следствия применения шаблона и разного рода компромиссы. Хотя при описании решений о последствиях часто не упоминают, знать о них необходимо, чтобы можно было выбирать между различными вариантами и оценивать преимущества и недостатки конкретного шаблона. Иногда в результатах может быть описан выбор языка и реализации. В случае проектирования к результатам относят влияние на степень гибкости, расширяемости и переносимости системы. Перечисление всех последствий помогает понять и оценить их роль.
Прото-шаблоны
Не всякое решение, алгоритм, лучшие практики или эвристики могут быть названы шаблоном. Один или несколько признаков шаблона могут отсутствовать. Даже если все признаки шаблона есть, но описанная проблема и/или решение не являются повторяющимися, предлагаемую идею нельзя назвать шаблоном. Существует мнение, что такой находящийся в разработке шаблон (прото-шаблон) должен быть применен по крайней мере трижды, просмотрен и одобрен значительным числом пользователей шаблонов. Краткое описание прото-шаблона называется patlet.
Топ шаблонов проектирования которые должен знать программист(старая версия)
Анти-шаблоны
В то время как обычный шаблон описывает положительный опыт решения задачи, анти-шаблоны описывают отрицательный опыт. Антишаблоны появились в середине 1990-х и не так многочисленны, как обычные шаблоны. Под анти-шаблонами понимают:
- шаблоны, описывающие плохое решение задачи, которое привело к печальным последствиям;
- шаблоны, описывающие выход из этого печального состояния и переход к хорошему решению.
Классификация шаблонов
Шаблоны можно классифицировать по применимости на этапах жизненного цикла программной системы:
- Шаблоны анализа.
- Шаблоны проектирования.
- Шаблоны реализации.
- Шаблоны тестирования.
Шаблоны анализа
Шаблоны анализа — набор концепций для решения типичной задачи бизнес-моделирования. Такие шаблоны могут быть специфичны для конкретной предметной области или могут использоваться для решения задач из разных предметных областей. К шаблонам, специфичным для конкретной предметной области, относятся, например, шаблон «диагностика» или «лечение» из области медицины. Иногда предметные области бывают идентичны с точки зрения анализа и используют одни и те же шаблоны. Так, шаблон «диагностика» может быть применен в области финансового анализа.
Шаблоны анализа имеют разную степень детализации.
Среди шаблонов анализа иногда выделяют шаблоны бизнес-процессов. Шаблоны бизнес-процессов включают шаблоны последовательностей, параллельного исполнения, синхронизации и множественного выбора, шаблоны отката и другие.
Шаблоны анализа иногда относят к шаблонам проектирования на концептуальном уровне.
Шаблоны проектирования
Шаблоны проектирования описывают периодически возникающую задачу проектирования информационной системы или ее составных частей, контекст задачи, принцип решения и положительный опыт решения, причем таким образом, что это решение может быть повторно использовано. Среди шаблонов проектирования иногда выделяют
Архитектурные шаблоны
Отражают фундаментальную структуру, схему информационной системы. Шаблоны описывают множество предопределенных подсистем, их функции и правила организации взаимодействия между подсистемами. То есть архитектурные шаблоны решают задачи проектирования системы на самом верхнем уровне абстракции.
Шаблоны логического проектирования
Эти шаблоны касаются деталей проектирования подсистем, компонент информационной системы и отношений между ними. Шаблоны проектирования описывают часто повторяющиеся структуры взаимодействующих компонент, решающих типичную задачу проектирования в конкретном контексте. Именно в этом смысле чаще всего употребляется термин «шаблон проектирования». В случае объектно-ориентированного проектирования шаблоны могут оперировать понятиями классов и объектов. Такие шаблоны наиболее полно исследованы и организованы в обширные библиотеки.
Идиомы (Idioms)
Идиомой называют шаблон низкого уровня, специфичный для конкретного языка программирования. Идиома описывает вопрос реализации компонент или взаимосвязей между ними с использованием возможностей конкретного языка. Граница между идиомами и шаблонами реализации очень условна. Часто идиомы относят к шаблонам реализации.
Шаблоны классифицируются не только по принадлежности к этапам жизненного цикла системы. Часто шаблоны классифицируются по типу решаемой задачи. Например, шаблоны организации распределенных вычислений, шаблоны пользовательского интерфейса, шаблоны данных, организационные шаблоны (описывают структуру проектной команды или организации в целом). Кроме того, выделяют шаблоны, относящиеся к конкретной парадигме программирования (объектно-ориентированные шаблоны) или концепции (шаблоны для сервисно-ориентированного подхода).
Системы шаблонов
Генерирующие шаблоны (generative patterns)
Большинство шаблонов являются генерирующими. То есть они описывают, что необходимо предпринять для решения задачи, и как мы можем сгенерировать решения и сами шаблоны (вспомним, что шаблон — это и сущность и процесс). Более того, в некоторых случаях такие шаблоны утверждают, что их необходимо создать. Генерирующие шаблоны описывают, как создать нечто, и затем могут быть выделены в итоговой системе (например, в ее архитектуре или процессах). Негенерирующие шаблоны могут не содержать указаний о том, как создавать описываемые ими сущности.
Генерирующие шаблоны являются основой и прообразом языков шаблонов.
Языки шаблонов
Набор шаблонов образует своеобразный словарь для обмена идеями, сочетания идей между собой и создания новых идей на основе предшествующих. Язык шаблонов включает в себя такой словарь (алфавит языка), набор правил образования новых шаблонов и правила преобразования шаблонов. Правила преобразования могут включать аксиомы и правила вывода.
Таким образом, язык шаблонов представляет собой формальную систему. В частности, это означает, что все шаблоны, полученные в результате выводов в такой системе, действительно будут шаблонами (а не прото-шаблонами или чем-то еще). Иногда в языки шаблонов вводят как самостоятельную сущность ограничения.
Каталоги и системы шаблонов
Каталоги шаблонов (библиотеки) — наборы взаимосвязанных шаблонов (связи могут быть слабыми и неформальными). Обычно каталог шаблонов поддерживает классификацию шаблонов и перекрестные ссылки между ними. Существует множество каталогов шаблонов в сети, печатных изданиях и других источниках.
Системы шаблонов представляют собой множество связных шаблонов, совместно решающих какую-либо задачу (например, задачу проектирования конкретного типа систем). Шаблоны в системе организованы в группы и подгруппы, отличаются уровнями детализации решаемых подзадач. Связи в системе имеют более тесный характер, чем в каталогах. Все шаблоны в системе единообразно описываются, причем особое внимание в описании уделяется вопросам отношений с другими шаблонами системы.
Итоги
В «хороших» проектах используется много шаблонов. Единое целое образуется в результате их согласованного взаимодействия. Применение шаблонов как повторное использование накопленного положительного опыта приносит очевидную пользу. Кроме того, изучение, классификация и выделение новых шаблонов ( pattern mining), по мнению многих авторов, сами по себе являются интересными и перспективными задачами.
Источник: intuit.ru
Организация исходного кода (шаблоны C++)
При определении шаблона класса необходимо организовать исходный код таким образом, чтобы определения элементов были видны компилятору, когда они ему нужны. Вы можете выбрать модель включения или модель явного создания экземпляра. В модели включения определения элементов включаются в каждый файл, использующий шаблон. Это самый простой подход.
Он обеспечивает максимальную гибкость с точки зрения того, какие конкретные типы могут использоваться в шаблоне. Его недостаток в том, что он может увеличивать время компиляции. Время может быть значительным, если проект или сами включенные файлы являются большими.
В рамках подхода явного создания экземпляров сам шаблон создает экземпляры конкретных классов или элементов класса для определенных типов. Этот подход может уменьшить время компиляции, но он ограничивает использование только теми классами, которые разработчик шаблона включил заранее. Как правило, модель включения рекомендуется использовать, если время компиляции не является проблемой.
История
Шаблоны не похожи на обычные классы в том смысле, что компилятор не создает объектный код для шаблона или любого из его членов. Создавать нечего, пока экземпляр шаблона не будет создан с конкретными типами. Когда компилятор обнаруживает создание экземпляра шаблона, такого как MyClass mc; , и класс с такой сигнатурой еще не существует, он создает такой класс.
Он также пытается создать код для любых используемых функций-элементов. Если эти определения находятся в файле, который прямо или косвенно не #included в компилируемых CPP-файлах, компилятор не сможет их увидеть. С точки зрения компилятора это не обязательно ошибка. Функции могут быть определены в другом блоке перевода, где компоновщик найдет их. Если компоновщик не находит этот код, возникает неразрешенная внешняя ошибка.
Модель включения
Самый простой и распространенный способ сделать определения шаблонов видимыми во всем блоке перевода — поместить определения в сам файл заголовка. Любой .cpp файл, использующий шаблон, просто должен иметь заголовок #include . Этот подход используется в стандартной библиотеке.
#ifndef MYARRAY #define MYARRAY #include template class MyArray < T arr[N]; public: // Full definitions: MyArray()<>void Print() < for (const auto v : arr) < std::cout > T return arr[i]; >>; #endif
При таком подходе компилятор имеет доступ к полному определению шаблона и может создавать экземпляры шаблонов по запросу для любого типа. Он прост и относительно прост в обслуживании.
Тем не менее модель включения затратнее с точки зрения времени компиляции. Эти затраты могут возрасти в крупных программах, особенно если сам заголовок шаблона содержит (#include) другие заголовки. Каждый .cpp файл, #includes заголовок, получит собственную копию шаблонов функций и всех определений. Компоновщик, как правило, сможет разобраться, чтобы не получить несколько определений для функции, но на выполнение этой работы требуется время. В случае небольших программ дополнительное время компиляции будет существенно меньше.
Модель явного создания экземпляра
Если модель включения не подходит для вашего проекта и вы точно знаете набор типов, которые будут использоваться для создания экземпляра шаблона, можно разделить код шаблона на .h файл и .cpp , а в .cpp файле явно создать экземпляр шаблонов. Этот подход создает объектный код, который будет видеть компилятор при обнаружении экземпляров пользователей.
Вы создаете явный экземпляр с помощью ключевое слово template за которым следует подпись сущности, которую вы хотите создать. Эта сущность может быть типом или членом. Если вы явно создаете экземпляр типа, будут созданы все элементы.
Файл заголовка MyArray.h объявляет класс MyArray шаблона :
//MyArray.h #ifndef MYARRAY #define MYARRAY template class MyArray < T arr[N]; public: MyArray(); void Print(); T >; #endif
Исходный файл MyArray.cpp явно создает template MyArray экземпляры и template MyArray :
//MyArray.cpp #include #include «MyArray.h» using namespace std; template MyArray::MyArray()<> template void MyArray::Print() < for (const auto v : arr) < cout cout template MyArray; template MyArray;
В предыдущем примере явные экземпляры находятся в нижней части .cpp файла. Можно MyArray использовать только для double типов или String .
В C++11 export ключевое слово не рекомендуется использовать в контексте определений шаблонов. На практике это мало что дает, потому что большинство компиляторов никогда его не поддерживали.
Источник: learn.microsoft.com
Основные архитектурные шаблоны построения ПО
Краткий обзор восьми наиболее востребованных архитектурных шаблонов с иллюстрациями:
- Многоуровневая архитектура;
- «Клиент-сервер»;
- «Каналы и фильтры»;
- «SOA»;
- «Издатель-подписчик»;
- «Общие данные»;
- «Одноранговая сеть»;
- «Брокер сервисов».
Использование шаблона проектирования можно сравнить с присутствием в вашей команде других архитекторов, от которых вы получаете знания, не вкладывая в это слишком много времени. В сфере разработки ПО существует масса всевозможных шаблонов, но в этой статье я решил сосредоточиться на наиболее используемых без привязки к конкретному языку.
Чем архитектурные шаблоны отличаются от шаблонов проектирования?
В названии статьи упоминаются архитектурные шаблоны, так что, думаю, следует прояснить их отличие от шаблонов проектирования, хотя это отличие может оказаться довольно неоднозначным. В первую очередь стоит отметить, что отличаются они типом решаемых с их помощью задач. Архитектурные шаблоны определяют решение для достижения различных качественных характеристик системы и подразумевают работу с несколькими компонентами ПО. В этом их область применения обширнее области шаблонов проектирования, которые предоставляют способ для структуризации классов с целью создания оптимальной внутренней структуры.
▍ Многоуровневый шаблон
Начнём с, пожалуй, наиболее востребованной многоуровневой архитектуры. Разделение системы на отдельные уровни с организацией внутри них компонентов по соответствующим критериям позволяет более слаженно взаимодействовать отдельным разработчикам и командам. В таком подходе уровни способствуют применению полезных практик слабого зацепления и высокой связности.
Строго говоря, в этой модели каждый модуль должен присваиваться только одному уровню, притом, что вышестоящие уровни могут использовать нижестоящие. Такая структура оправдывает себя в плане обслуживаемости, позволяя разным командам параллельно работать над разными модулями. Вот пример подобной схемы:
Многоуровневый шаблон
API взаимодействует с сервисами бизнес-логики, которые, в свою очередь, обращаются к уровню данных. При этом все они могут иметь общий набор библиотек для повторного использования компонентов.
▍ Шаблон «Клиент-сервер»
Тоже очень распространённый шаблон, в котором сервер предлагает один или более сервисов, потребляемых одним или более клиентами. Будучи простой, но в то же время очень мощной, эта модель даёт возможность построения распределённых систем, в которых сервер централизует ресурсы и рабочую нагрузку в одном месте, позволяя множеству потребителей использовать эти данные независимо.
На основе этого механизма работают мобильные приложения, Twitter, Medium, электронная почта, обмен файлами и Web в целом. В таком контексте пользовательские приложения потребляют данные и предоставляют интерфейс для взаимодействия с ними, в результате чего клиент и сервер формируют общую систему. Однако в рамках этого шаблона есть строгое распределение обязанностей и ответственностей.
Шаблон «Клиент-сервер»
▍ Шаблон «Каналы и фильтры»
В случае шаблона «Каналы и фильтры» каждый компонент-фильтр отвечает за одно преобразование данных или операцию с ними. Данные передаются от одного фильтра следующему максимально быстро, и операция над ними выполняется параллельно. Раздельные фильтры даже можно повторно использовать и менять местами для создания новых пайплайнов.
Этот шаблон широко применяется в анализе и преобразовании данных. Наиболее же типичный пример — это использование Unix-функции pipe для комбинирования команд — суть та же.
Шаблон «Каналы и фильтры»
- фильтр: компонент, который считывает данные, преобразует их и возвращает результат;
- канал: связующий компонент, переносящий данные от одного фильтра к другому и гарантирующий их неизменность на этом пути.
▍ Шаблон SOA
В сервис-ориентированной архитектуре (SOA) независимые компоненты реализуются в виде сервисов, что предоставляет специфическую функциональность. Эти сервисы совмещаются в среде выполнения, определяя поведение системы в целом. Чтобы это сработало, потребители сервисов должны иметь возможность обнаруживать и использовать их, не зная деталей реализации.
Построить такую архитектуру можно по-разному.
Традиционные системы SOA в основном опираются на протокол SOAP, который работает путём обмена XML-сообщениями, а более «современные» приложения ориентированы на использование микросервисов, которые связываются легковесными сообщениями, передаваемыми по протоколу вроде HTTP.
Ниже приведён упрощённый пример представления системы SOA. На практике же подобные архитектуры сложны и включают множество компонентов. На схеме мы видим два сервиса, подключённых к общему реестру сервисов. Через этот реестр они при необходимости находят информацию для подключения друг к другу.
Обобщённый пример SOA
Эта архитектура повышает функциональную совместимость и масштабируемость системы, но также привносит сложность в процесс определения и интеграции распределённых систем, поскольку зачастую нелегко управлять изменениями в сообщениях, которые могут повлиять на потребителей разных сервисов.
▍ Шаблон «Издатель-подписчик»
В шаблоне «Издатель-подписчик» издатели и потребители данных существуют независимо и являются друг для друга анонимными. В рамках этого шаблона множество потребителей подписываются на события, публикуемые множеством издателей. Обе стороны взаимодействуют опосредованно через шину событий.
Поскольку все взаимодействия реализуются через шину событий, то к ней должны быть подключены все участники. Причём для успешной работы здесь важен правильный выбор подходящей технологии. Ниже показан пример такой системы, в которой разные типы устройств подключены к шине событий.
Шаблон «Издатель-подписчик»
Эта архитектура повышает переиспользуемость и быстродействие при обмене данными, оптимизируя их создание и потребление на шине событий. Однако сложно рассуждать о производительности таких систем, учитывая асинхронную природу коммуникаций. В конечном счёте шина событий оказывается узким местом в системах как с высоким, так и с низким быстродействием.
▍ Шаблон «Общие данные»
В шаблоне «Общие данные» несколько компонентов обращаются к набору данных через общее хранилище. При этом ни один из компонентов не несёт полной ответственности за сами данные или хранилище, так как они являются общими. Такой шаблон особенно эффективен в случаях, когда множеству компонентов требуется доступ к большим объёмам данных.
Шаблон «Общие данные»
И хотя эта схема имеет собственное название, обычно мы видим её в составе более крупных систем, например, когда в архитектуре SOA разные сервисы обращаются к общей базе данных. В таком случае можно определить типы доступа как чтение и запись, установив разные правила и разрешения, оптимизирующие и защищающие доступ к данным. Сегодня сложность этой архитектуры понижается, к примеру, с помощью облачных сервисов вроде AWS RDS, которые обеспечивают для баз данных работу с репликами, масштабируемость и резервное копирование.
Этот шаблон повышает надёжность за счёт согласованности данных, а также масштабируемость и быстродействие в случае их правильной разбивки. С другой стороны, в случае некорректного управления системой существует единая точка отказа.
▍ Шаблон P2P
Одноранговые архитектурные шаблоны принадлежат к категории симметричных шаблонов «Клиент-сервер». Симметричность в данном контексте означает отсутствие в сети подразделения на клиентов и серверы. В этом шаблоне одна система выступает и как клиент, и как сервер.
Каждая система, также называемая пиром, отправляет запросы другим пирам сети и в то же время получает и обслуживает запросы от других пиров этой сети. Такая схема сильно отличается от традиционной клиент-серверной сети, в которой клиент должен только отправлять запрос и ожидать его обработки сервером.
Одноранговая архитектура
Примеры этой архитектуры можно наблюдать в сетях обмена файлами вроде Gnutella, а также протоколе блокчейна и его реализации Bitcoin.
▍ Шаблон «Брокер сервисов»
Брокерская система включает в себя три основных компонента: брокера, сервер и клиента. Этот шаблон используется для структуризации распределённых систем с раздельными компонентами. На определённом уровне он является расширением клиент-серверного подхода для более сложных сценариев.
Брокер – это компонент, отвечающий за переправку сообщений между клиентом и сервером. Эти сообщения представляют собой запросы к сервисам и ответы на них, а также отчёты о возникших исключениях.
Серверы размещают информацию о своих возможностях (сервисы и характеристики) на брокере, который при получении от клиента определённого запроса перенаправляет этого клиента в подходящий сервис из имеющихся в реестре. Хорошими примерами брокеров сообщений являются Apache ActiveMQ, Apache Kafka, RabbitMQ.
Схематично шаблон выглядит так:
Шаблон «Брокер сервисов»
Использовать этот шаблон рекомендуется, когда связь между клиентом и сервером не является фиксированной ввиду присутствия нескольких подходящих серверов или их периодического изменения. Он также актуален, если выбор сервера зависит от определённого критерия, который достаточно сложен для передачи отдельному компоненту. Что же касается настройки или создания брокера, то это сложная задача, которая обычно выполняется одним из провайдеров вроде упомянутых выше.
▍ Поиск подходящей архитектуры
Список шаблонов можно продолжать и продолжать. В действительности я перечислил лишь те, что считаю наиболее распространёнными. Некоторые шаблоны рождаются в ходе решения новых задач, другие могут подходить для различных систем или команд, а третьи лишь одной организации. Важно объективно оценивать структуру вашей системы, а также обращаться к опыту других людей, знакомых с областью стоящей перед вами задачи. Скорее всего, ваше решение потребует комбинирования нескольких из перечисленных шаблонов, ибо сложность является неизбежным фактором во всех успешных системах ПО.
▍ Бонус: несоответствие архитектуры
Архитектурное несоответствие – это феномен, который очень часто встречается при проектировании архитектуры, в которой предполагается, что компонент будет использоваться способом, противоречащим его базовому назначению. В результате возрастает сложность не только разработки архитектуры, но и её обслуживания, что делает невозможным достижение необходимых критериев качества.
Такая ситуация может сложиться на концептуальном уровне, когда архитектурная схема не сопоставлена с наиболее важными атрибутами создаваемой системы, или когда выбрана неподходящая технология. Например, если ничто не указывает на связь архитектуры с моделью издатель-подписчик, то использование реляционной базы данных в качестве основного механизма обмена сообщениями существенно скажется на итоговом результате.
Изучение шаблонов и выделение необходимого времени на подобающее определение архитектуры может избавить от множества проблем, так что не стоит недооценивать этот этап в начале каждого проекта. Даже выбор необходимых технологий нужно производить лишь тогда, когда определена архитектура, но не наоборот, как это часто бывает.
Вот, собственно, и всё. Благодарю за внимание!
Источник: habr.com