В программной инженерии шаблон проектирования описывает относительно небольшой, четко определенный аспект (т. е. функциональность) компьютерной программы с точки зрения того, как писать код .
Использование шаблона направлено на использование существующей концепции , а не на ее переизобретение . Это может сократить время разработки программного обеспечения и повысить качество получаемой программы.
Примечательно, что шаблон не состоит из программного артефакта . Большинство ресурсов разработки, которые использует программист , включают настройку кодовой базы для использования артефакта; например, библиотеки . Напротив, для использования шаблона программист пишет код, как описано в шаблоне. Результат каждый раз уникален, даже если результат может быть распознан как основанный на шаблоне.
Некоторые считают использование шаблонов лучшим методом проектирования программного обеспечения . Некоторые рассматривают использование шаблонов проектирования как структурированный подход к программированию .
Концептуально шаблон проектирования можно описать как более конкретный, чем парадигма программирования , и менее конкретный, чем алгоритм .
Паттерны возникли как архитектурная концепция Кристофера Александера еще в 1977 году в A Pattern Language (см. его статью "The Pattern of Streets", JOURNAL OF THE AIP, сентябрь 1966 г., том 32, № 5, стр. 273–278). В 1987 году Кент Бек и Уорд Каннингем начали экспериментировать с идеей применения паттернов к программированию — в частности, языков паттернов — и представили свои результаты на конференции OOPSLA в том же году. [1] [2] В последующие годы Бек, Каннингем и другие продолжили эту работу.
Шаблоны проектирования приобрели популярность в информатике после того, как в 1994 году так называемая «Банда четырех» (Гамма и др.) опубликовала книгу « Шаблоны проектирования: элементы многоразового объектно-ориентированного программного обеспечения », которую часто сокращают до «GoF». В том же году прошла первая конференция Pattern Languages of Programming , а в следующем году был создан Portland Pattern Repository для документирования шаблонов проектирования. Область применения термина остается предметом споров. Известные книги в жанре шаблонов проектирования включают:
Хотя шаблоны проектирования применяются на практике уже давно, формализация концепции шаблонов проектирования затянулась на несколько лет. [3]
Шаблоны проектирования могут ускорить процесс разработки, предоставляя проверенные парадигмы разработки. [4] Эффективное проектирование программного обеспечения требует рассмотрения проблем, которые могут не проявиться до поздней стадии реализации. Свеженаписанный код часто может иметь скрытые, тонкие проблемы, обнаружение которых занимает время; проблемы, которые иногда могут вызвать серьезные проблемы в будущем. Повторное использование шаблонов проектирования может помочь предотвратить такие проблемы, [5] и улучшить читаемость кода для тех, кто знаком с шаблонами.
Методы проектирования программного обеспечения трудно применять к более широкому кругу проблем. [ необходима ссылка ] Шаблоны проектирования предоставляют общие решения, задокументированные в формате, который не требует конкретики, привязанной к конкретной проблеме.
В 1996 году Кристофер Александр был приглашен выступить с программной речью на съезде OOPSLA 1996 года. Здесь он размышлял о том, как развивалась его работа над шаблонами в архитектуре, и о своих надеждах на то, как сообщество разработчиков программного обеспечения может помочь архитектуре расширить шаблоны для создания живых структур, использующих генеративные схемы, которые больше похожи на компьютерный код.
Шаблон описывает мотив дизайна , также известный как прототипическая микроархитектура , как набор компонентов программы (например, классов, методов...) и их взаимосвязей. Разработчик адаптирует мотив к своей кодовой базе для решения проблемы, описанной шаблоном. Полученный код имеет структуру и организацию, схожие с выбранным мотивом.
Также были предприняты усилия по кодификации шаблонов дизайна в определенных доменах, включая использование существующих шаблонов дизайна, а также шаблонов дизайна, специфичных для домена. Примерами являются шаблоны дизайна пользовательского интерфейса , [6] визуализация информации , [7] безопасный дизайн, [8] «безопасное удобство использования», [9] веб-дизайн [10] и дизайн бизнес-моделей. [11]
Ежегодные материалы конференции Pattern Languages of Programming [12] включают множество примеров шаблонов, специфичных для предметной области.
Объектно-ориентированные шаблоны проектирования обычно показывают отношения и взаимодействия между классами или объектами , не указывая конечные классы или объекты приложения, которые задействованы. Шаблоны, подразумевающие изменяемое состояние, могут быть неподходящими для функциональных языков программирования. Некоторые шаблоны могут оказаться ненужными в языках, имеющих встроенную поддержку для решения проблемы, которую они пытаются решить, а объектно-ориентированные шаблоны не обязательно подходят для необъектно-ориентированных языков.
Шаблоны проектирования можно организовать в группы на основе того, какую проблему они решают. Творческие шаблоны создают объекты. Структурные шаблоны организуют классы и объекты для формирования более крупных структур, которые предоставляют новую функциональность. Поведенческие шаблоны обеспечивают связь между объектами и реализацию этих шаблонов.
Имя | Описание | В шаблонах проектирования | В коде завершено [13] | Другой |
---|---|---|---|---|
Абстрактная фабрика | Предоставляет интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов. | Да | Да | — |
Строитель | Отделите построение сложного объекта от его представления, позволяя одному и тому же процессу построения создавать различные представления. | Да | Да | — |
Внедрение зависимости | Класс принимает требуемые ему объекты от инжектора вместо того, чтобы создавать объекты напрямую. | — | Да | — |
Заводской метод | Определите интерфейс для создания одного объекта, но позвольте подклассам решать, какой класс инстанцировать. Фабричный метод позволяет классу отложить инстанцирование подклассам. | Да | Да | — |
Ленивая инициализация | Тактика откладывания создания объекта, вычисления значения или какого-либо другого дорогостоящего процесса до первого раза, когда это понадобится. Этот шаблон появляется в каталоге GoF как "виртуальный прокси", стратегия реализации для шаблона Proxy . | Да | Да | PoEAA [14] |
Многотонный | Убедитесь, что класс имеет только именованные экземпляры, и предоставьте глобальную точку доступа к ним. | Да | Да | Да |
Объектный пул | Избегайте дорогостоящего приобретения и освобождения ресурсов путем переработки объектов, которые больше не используются. Можно считать обобщением шаблонов пула соединений и пула потоков . | Да | Да | Да |
Прототип | Укажите типы объектов, которые необходимо создать, используя прототипный экземпляр, и создавайте новые объекты из «скелета» существующего объекта, тем самым повышая производительность и сводя к минимуму потребление памяти. | Да | Да | Да |
Получение ресурсов — инициализация (RAII) | Обеспечьте правильное высвобождение ресурсов, привязав их к сроку службы подходящих объектов. | Да | Да | Да |
Синглтон | Убедитесь, что класс имеет только один экземпляр, и предоставьте глобальную точку доступа к нему. | Да | Да | Да |
Имя | Описание | В шаблонах проектирования | В коде завершено [13] | Другой |
---|---|---|---|---|
Адаптер , оболочка или транслятор | Преобразовать интерфейс класса в другой интерфейс, ожидаемый клиентами. Адаптер позволяет классам работать вместе, что в противном случае было бы невозможно из-за несовместимых интерфейсов. Эквивалент шаблона интеграции предприятия — транслятор. | Да | Да | Да |
Мост | Отделите абстракцию от ее реализации, позволив им изменяться независимо. | Да | Да | Да |
Композитный | Составляйте объекты в древовидные структуры для представления иерархий часть-целое. Composite позволяет клиентам обрабатывать отдельные объекты и композиции объектов единообразно. | Да | Да | Да |
Декоратор | Прикрепите дополнительные обязанности к объекту, динамически сохраняя тот же интерфейс. Декораторы предоставляют гибкую альтернативу подклассификации для расширения функциональности. | Да | Да | Да |
Делегация | Расширить класс путем композиции вместо подклассификации. Объект обрабатывает запрос путем делегирования второму объекту (делегату) | Да | Да | Да |
Объект расширения | Добавление функциональности в иерархию без изменения самой иерархии. | Да | Да | Да |
Фасад | Предоставляет унифицированный интерфейс для набора интерфейсов в подсистеме. Фасад определяет интерфейс более высокого уровня, который упрощает использование подсистемы. | Да | Да | Да |
Наилегчайший вес | Используйте совместное использование для эффективной поддержки большого количества однотипных объектов. | Да | Да | Да |
Передний контроллер | Шаблон относится к проектированию веб-приложений. Он обеспечивает централизованную точку входа для обработки запросов. | Да | Да | Шаблоны J2EE [15] PoEAA [16] |
Маркер | Пустой интерфейс для связывания метаданных с классом. | Да | Да | Эффективная Java [17] |
Модуль | Объедините несколько связанных элементов, таких как классы, синглтоны, методы, используемые глобально, в одну концептуальную сущность. | Да | Да | Да |
Прокси | Предоставьте суррогат или заполнитель для другого объекта, чтобы контролировать доступ к нему. | Да | Да | Да |
Близнец [18] | Twin позволяет моделировать множественное наследование в языках программирования, которые не поддерживают эту функцию. | Да | Да | Да |
Имя | Описание | В шаблонах проектирования | В коде завершено [13] | Другой |
---|---|---|---|---|
Доска | Модель искусственного интеллекта для объединения разнородных источников данных (см. систему «доска» ) | Да | Да | Да |
Цепочка ответственности | Избегайте связывания отправителя запроса с его получателем, давая возможность обработать запрос нескольким объектам. Объедините получающие объекты в цепочку и передавайте запрос по цепочке, пока объект его не обработает. | Да | Да | Да |
Команда | Инкапсулировать запрос как объект, тем самым позволяя параметризацию клиентов с различными запросами, а также постановку в очередь или регистрацию запросов. Это также позволяет поддерживать отменяемые операции. | Да | Да | Да |
Удобный интерфейс | Разработайте API, чтобы он был связан в цепочку методов, чтобы он читался как DSL. Каждый вызов метода возвращает контекст, через который становятся доступными следующие логические вызовы методов. | Да | Да | Да |
Устный переводчик | Для заданного языка определите представление его грамматики, а также интерпретатор, который использует это представление для интерпретации предложений на этом языке. | Да | Да | Да |
Итератор | Предоставьте способ последовательного доступа к элементам совокупного объекта , не раскрывая его базовое представление. | Да | Да | Да |
Посредник | Определите объект, который инкапсулирует способ взаимодействия набора объектов. Медиатор способствует слабой связанности , не давая объектам явно ссылаться друг на друга, и позволяет их взаимодействию изменяться независимо. | Да | Да | Да |
Памятка | Не нарушая инкапсуляции, захватить и экстернализировать внутреннее состояние объекта, позволяя впоследствии восстановить объект в этом состоянии. | Да | Да | Да |
Нулевой объект | Избегайте нулевых ссылок, предоставляя объект по умолчанию. | Да | Да | Да |
Наблюдатель или публикация/подписка | Определите зависимость «один ко многим» между объектами, при которой изменение состояния одного объекта приводит к автоматическому уведомлению и обновлению всех его зависимых объектов. | Да | Да | Да |
Слуга | Определить общую функциональность для группы классов. Шаблон слуги также часто называют реализацией вспомогательного класса или класса утилиты для заданного набора классов. Вспомогательные классы обычно не имеют объектов, поэтому у них есть все статические методы, которые действуют на различные виды объектов класса. | Да | Да | Да |
Спецификация | Рекомбинируемая бизнес-логика в булевском стиле. | Да | Да | Да |
Состояние | Разрешить объекту изменять свое поведение при изменении его внутреннего состояния. Объект будет выглядеть так, будто меняет свой класс. | Да | Да | Да |
Стратегия | Определите семейство алгоритмов, инкапсулируйте каждый из них и сделайте их взаимозаменяемыми. Стратегия позволяет алгоритму изменяться независимо от клиентов, которые его используют. | Да | Да | Да |
Метод шаблона | Определить скелет алгоритма в операции, отложив некоторые шаги в подклассы. Шаблонный метод позволяет подклассам переопределять некоторые шаги алгоритма, не меняя структуру алгоритма. | Да | Да | Да |
Посетитель | Представляет операцию, которая должна быть выполнена над экземплярами набора классов. Посетитель позволяет определить новую операцию, не изменяя классы элементов, над которыми она работает. | Да | Да | Да |
Имя | Описание | В POSA2 [19] | Другой |
---|---|---|---|
Активный объект | Разделяет выполнение метода от вызова метода, которые находятся в собственном потоке управления. Цель состоит в том, чтобы ввести параллелизм, используя асинхронный вызов метода и планировщик для обработки запросов. | Да | — |
Уклоняться | Выполняйте действие над объектом только тогда, когда объект находится в определенном состоянии. | Нет | — |
Связующие свойства | Объединение нескольких наблюдателей для принуждения свойств различных объектов синхронизироваться или координироваться каким-либо образом. [20] | Нет | — |
Вычислительное ядро | Одно и то же вычисление много раз параллельно, отличающееся целочисленными параметрами, используемыми с неветвящейся математикой указателей в общих массивах, например, оптимизированное для GPU матричное умножение или сверточная нейронная сеть . | Нет | — |
Двойная проверка блокировки | Уменьшите накладные расходы на получение блокировки, сначала проверив критерий блокировки («подсказку о блокировке») небезопасным способом; только в случае успешного выполнения будет продолжена фактическая логика блокировки. Может быть небезопасным при реализации в некоторых языковых/аппаратных комбинациях. Поэтому иногда его можно считать анти-шаблоном . | Да | — |
Асинхронный на основе событий | Решает проблемы с асинхронным шаблоном, возникающие в многопоточных программах. [21] | Нет | — |
Охраняемая подвеска | Управляет операциями, требующими как получения блокировки, так и выполнения предварительного условия перед выполнением операции. | Нет | — |
Присоединиться | Join-pattern предоставляет способ писать параллельные, параллельные и распределенные программы с помощью передачи сообщений. По сравнению с использованием потоков и блокировок, это высокоуровневая модель программирования. | Нет | — |
Замок | Один поток устанавливает «блокировку» на ресурс, не позволяя другим потокам получать к нему доступ или изменять его. [22] | Нет | PoEAA [14] |
Шаблон проектирования обмена сообщениями (MDP) | Позволяет осуществлять обмен информацией (т. е. сообщениями) между компонентами и приложениями. | Нет | — |
Объект мониторинга | Объект, методы которого подлежат взаимному исключению , что предотвращает возможность ошибочной попытки его использования несколькими объектами одновременно. | Да | — |
Реактор | Объект реактора предоставляет асинхронный интерфейс для ресурсов, которые должны обрабатываться синхронно. | Да | — |
Блокировка чтения-записи | Позволяет одновременный доступ на чтение к объекту, но требует исключительного доступа для операций записи. Для записи может использоваться базовый семафор, а механизм копирования при записи может использоваться или не использоваться. | Нет | — |
Планировщик | Явно контролируйте, когда потоки могут выполнять однопоточный код. | Нет | — |
Шаблон обработчика услуг | Для каждого запроса сервер создает выделенный клиентский обработчик для обработки запроса. [23] Также называется потоком на сеанс . [24] | Нет | — |
Пул потоков | Для выполнения ряда задач создается ряд потоков, которые обычно организуются в очередь. Обычно задач гораздо больше, чем потоков. Можно считать частным случаем шаблона пула объектов . | Нет | — |
Хранилище, специфичное для потока | Статическая или «глобальная» память, локальная для потока. | Да | — |
Безопасный параллелизм с исключительным правом собственности | Избегание необходимости в параллельных механизмах времени выполнения, поскольку можно доказать исключительное владение. Это примечательная возможность языка Rust, но проверка во время компиляции — не единственное средство, программист часто вручную проектирует такие шаблоны в коде — опуская использование механизма блокировки, поскольку программист оценивает, что данная переменная никогда не будет доступна одновременно. | Нет | — |
Атомарные операции ЦП | x86 и другие архитектуры ЦП поддерживают ряд атомарных инструкций, которые гарантируют безопасность памяти для изменения и доступа к примитивным значениям (целым числам). Например, два потока могут оба безопасно увеличивать счетчик. Эти возможности также могут использоваться для реализации механизмов для других шаблонов параллелизма, как указано выше. Язык C# использует класс Interlocked для этих возможностей. | Нет | — |
Документация для шаблона проектирования описывает контекст, в котором используется шаблон, силы в контексте, которые шаблон стремится разрешить, и предлагаемое решение. [25] Не существует единого стандартного формата для документирования шаблонов проектирования. Скорее, различные авторы шаблонов использовали множество различных форматов. Однако, по словам Мартина Фаулера , некоторые формы шаблонов стали более известными, чем другие, и, следовательно, стали общими отправными точками для новых усилий по написанию шаблонов. [26] Одним из примеров широко используемого формата документации является тот, который использовали Эрих Гамма , Ричард Хелм , Ральф Джонсон и Джон Влиссидес в своей книге Design Patterns . Она содержит следующие разделы:
Некоторые предполагают, что шаблоны проектирования могут быть признаком того, что в данном языке программирования отсутствуют функции ( например, Java или C++ ). Питер Норвиг демонстрирует, что 16 из 23 шаблонов в книге Design Patterns (которая в первую очередь сосредоточена на C++) упрощены или устранены (через прямую языковую поддержку) в Lisp или Dylan . [27] Связанные наблюдения были сделаны Ханнеманом и Кичалесом, которые реализовали несколько из 23 шаблонов проектирования с использованием аспектно-ориентированного языка программирования (AspectJ) и показали, что зависимости на уровне кода были удалены из реализаций 17 из 23 шаблонов проектирования и что аспектно-ориентированное программирование может упростить реализацию шаблонов проектирования. [28] См. также эссе Пола Грэма «Месть ботаников». [29]
Неправильное использование шаблонов может привести к неоправданному увеличению сложности. [30]
По определению, шаблон должен быть запрограммирован заново в каждом приложении, которое его использует. Поскольку некоторые авторы видят в этом шаг назад от повторного использования программного обеспечения , предоставляемого компонентами , исследователи работали над тем, чтобы превратить шаблоны в компоненты. Мейер и Арноут смогли обеспечить полную или частичную компонентизацию двух третей шаблонов, которые они пытались реализовать. [31]
Для достижения гибкости шаблоны проектирования могут вводить дополнительные уровни косвенности , что может усложнить конечный проект и снизить производительность выполнения .
Уорд предостерег от требования слишком большого программирования на, как он выразился, «высоком уровне мастеров». Он указал, что письменный «язык шаблонов» может значительно улучшить выбор и применение абстракций. Он предложил «радикальный сдвиг в бремени проектирования и реализации», основывая новую методологию на адаптации работы Кристофера Александра в языках шаблонов, и что ориентированные на программирование языки шаблонов, разработанные в
Tektronix,
значительно помогли их усилиям по разработке программного обеспечения.
Если вы хотите ускорить разработку приложений .NET, вы готовы к шаблонам проектирования C# — элегантным, общепринятым и проверенным способам решения распространенных проблем программирования.
5.1 Популярные шаблоны проектирования