Паттерн что это такое в программировании


Шаблон проектирования — Википедия

Название Оригинальное название Описание Описан в Design Patterns
Основные шаблоны (Fundamental)
Шаблон делегирования Delegation pattern Объект внешне выражает некоторое поведение, но в реальности передаёт ответственность за выполнение этого поведения связанному объекту. н/д
Шаблон функционального дизайна Functional design Гарантирует, что каждый модуль компьютерной программы имеет только одну обязанность и исполняет её с минимумом побочных эффектов на другие части программы. н/д
Неизменяемый интерфейс Immutable interface Создание неизменяемого объекта. н/д
Интерфейс Interface Общий метод для структурирования компьютерных программ для того, чтобы их было проще понять. н/д
Интерфейс-маркер Marker interface В качестве атрибута (как пометки объектной сущности) применяется наличие или отсутствие реализации интерфейса-маркера. В современных языках программирования вместо этого могут применяться атрибуты или аннотации. н/д
Контейнер свойств Property container Позволяет добавлять дополнительные свойства для класса в контейнер (внутри класса), вместо расширения класса новыми свойствами. н/д
Канал событий Event channel Расширяет шаблон Publish/Subscribe, создавая централизованный канал для событий. Использует объект-представитель для подписки и объект-представитель для публикации события в канале. Представитель существует отдельно от реального издателя или подписчика. Подписчик может получать опубликованные события от более чем одного объекта, даже если он зарегистрирован только на одном канале. н/д
Порождающие шаблоны (Creational) — шаблоны проектирования, которые абстрагируют процесс инстанцирования. Они позволяют сделать систему независимой от способа создания, композиции и представления объектов. Шаблон, порождающий классы, использует наследование, чтобы изменять инстанцируемый класс, а шаблон, порождающий объекты, делегирует инстанцирование другому объекту.
Абстрактная фабрика Abstract factory Класс, который представляет собой интерфейс для создания компонентов системы. Да
Строитель Builder Класс, который представляет собой интерфейс для создания сложного объекта. Да
Фабричный метод Factory method Определяет интерфейс для создания объекта, но оставляет подклассам решение о том, какой класс инстанцировать. Да
Отложенная инициализация Lazy initialization Объект, инициализируемый во время первого обращения к нему. Нет
Мультитон Multiton Гарантирует, что класс имеет поименованные экземпляры объекта и обеспечивает глобальную точку доступа к ним. Нет
Объектный пул Object pool Класс, который представляет собой интерфейс для работы с набором инициализированных и готовых к использованию объектов. Нет
Прототип Prototype Определяет интерфейс создания объекта через клонирование другого объекта вместо создания через конструктор. Да
Получение ресурса есть инициализация Resource acquisition is initialization (RAII) Получение некоторого ресурса совмещается с инициализацией, а освобождение — с уничтожением объекта. Нет
Одиночка Singleton Класс, который может иметь только один экземпляр. Да
Структурные шаблоны (Structural) определяют различные сложные структуры, которые изменяют интерфейс уже существующих объектов или его реализацию, позволяя облегчить разработку и оптимизировать программу.
Адаптер Adapter / Wrapper Объект, обеспечивающий взаимодействие двух других объектов, один из которых использует, а другой предоставляет несовместимый с первым интерфейс. Да
Мост Bridge Структура, позволяющая изменять интерфейс обращения и интерфейс реализации класса независимо. Да
Компоновщик Composite Объект, который объединяет в себе объекты, подобные ему самому. Да
Декоратор или Wrapper/Обёртка Decorator Класс, расширяющий функциональность другого класса без использования наследования. Да
Фасад Facade Объект, который абстрагирует работу с несколькими классами, объединяя их в единое целое. Да
Единая точка входа Front controller Обеспечивает унифицированный интерфейс для интерфейсов в подсистеме. Front Controller определяет высокоуровневый интерфейс, упрощающий использование подсистемы. Нет
Приспособленец Flyweight Это объект, представляющий себя как уникальный экземпляр в разных местах программы, но фактически не являющийся таковым. Да
Заместитель Proxy Объект, который является посредником между двумя другими объектами, и который реализует/ограничивает доступ к объекту, к которому обращаются через него. Да
Поведенческие шаблоны (Behavioral) определяют взаимодействие между объектами, увеличивая таким образом его гибкость.
Цепочка обязанностей Chain of responsibility Предназначен для организации в системе уровней ответственности. Да
Команда, Action, Transaction Command Представляет действие. Объект команды заключает в себе само действие и его параметры. Да
Интерпретатор Interpreter Решает часто встречающуюся, но подверженную изменениям, задачу. Да
Итератор, Cursor Iterator Представляет собой объект, позволяющий получить последовательный доступ к элементам объекта-агрегата без использования описаний каждого из объектов, входящих в состав агрегации. Да
Посредник Mediator Обеспечивает взаимодействие множества объектов, формируя при этом слабую связанность и избавляя объекты от необходимости явно ссылаться друг на друга. Да
Хранитель Memento Позволяет не нарушая инкапсуляцию зафиксировать и сохранить внутренние состояния объекта так, чтобы позднее восстановить его в этих состояниях. Да
Null Object Null Object Предотвращает нулевые указатели, предоставляя объект «по умолчанию». Нет
Наблюдатель или Издатель-подписчик Observer Определяет зависимость типа «один ко многим» между объектами таким образом, что при изменении состояния одного объекта все зависящие от него оповещаются об этом событии. Да
Слуга[en] Servant Используется для обеспечения общей функциональности группе классов. Нет
Спецификация Specification Служит для связывания бизнес-логики. Нет
Состояние State Используется в тех случаях, когда во время выполнения программы объект должен менять своё поведение в зависимости от своего состояния. Да
Стратегия Strategy Предназначен для определения семейства алгоритмов, инкапсуляции каждого из них и обеспечения их взаимозаменяемости. Да
Шаблонный метод Template method Определяет основу алгоритма и позволяет наследникам переопределять некоторые шаги алгоритма, не изменяя его структуру в целом. Да
Посетитель Visitor Описывает операцию, которая выполняется над объектами других классов. При изменении класса Visitor нет необходимости изменять обслуживаемые классы. Да
Простая политика Simple Policy Нет
Event listener Event listener Нет
Одноразовый посетитель[en] Single-serving visitor Оптимизирует реализацию шаблона посетитель, который инициализируется, единожды используется, и затем удаляется. Нет
Иерархический посетитель[en] Hierarchical visitor Предоставляет способ обхода всех вершин иерархической структуры данных (напр. древовидной). Нет

Паттерны ООП простыми словами: порождающие паттерны

Привести в пример паттерн проектирования – один из самых популярных запросов на собеседованиях. Объясняем порождающие паттерны простыми словами.

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

Вы хотите создать автомобиль, но поняитя не имеете, с чего начать. Сколько должно быть у него колес? 3, 4, 5? Вы не знаете точно, потому что никогда до этого не занимались проектированием автомобилей. К счастью, до вас люди занимались этим десятилетиями и вы точно знаете, что для конкретно вашего варианта автомобиля потребуется база из 4 колес. Вам не нужно экспериментировать и строить трицикл, чтобы убедиться в его неэффективности.

Паттерны не привязаны к конкретному языку программирования, это просто подход к проектированию.

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

Singleton (одиночка)

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

Здесь нам пригодится паттерн «Одиночка». Одиночкой в этом случае будет телефонная станция, и все линии связи будут проходить через нее. Для добавления нового жителя потребуется только протянуть кабель от его дома до станции.

Но главное в одиночке то, что создав станцию один раз, ей может пользоваться сколько угодно людей. Смысл в том, что когда вы скажете «Мне нужна телефонная станция», вам ответят не «Нужно построить новую», а «Она находится там-то».

Registry (реестр, журнал записей)

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

Еще один пример одиночки-реестра – бухгалтерия. Фирма не создает бухгалтерию каждый раз, когда она ей понадобится. В то же время, в бухгалтерии хранятся записи обо всех сотрудниках фирмы, как в реестре.

Multiton (пул «одиночек»)

По сути данный паттерн – это реестр одиночек, каждый из которых имеет имя, по которому к нему можно получить доступ.

Object pool (пул объектов)

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

Factory (фабрика)

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

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

Builder (строитель)

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

Prototype (прототип)

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

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

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

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

Допустим фабрика производит пакеты с разными соками. Мы можем на каждый вид сока сделать свою производственную линию, но это не эффективно. Удобнее сделать одну линию по производству пакетов-основ, а разделение ввести только на этапе заливки сока, который мы можем определять просто по названию сока.

Для этого мы создаем основной отдел по производству пакетов-основ и предупреждаем все подотделы, что они должны производить нужный пакет с соком про простому «Надо» (т.е. каждый подотдел должен реализовать паттерн «фабричный метод»). Поэтому каждый подотдел заведует только своим типом сока и реагирует на слово «Надо».

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

Lazy initialization (отложенная инициализация)

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

Dependency injection (внедрение зависимости)

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

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

Паттерны проектирования • Vertex Academy

Данная статья:


Данной статьей мы начинаем серию статей, посвященных паттернам проектирования.

Статьи рассчитаны на тех, кто уже хорошо знает ООП.

Ну, что ж, давайте сначала разберемся что такое паттерн. А затем плавно перейдем к такому понятию как "паттерны в программировании".

Паттерн - это повторяющийся элемент в различных сферах жизни.

Пример 1: окрас тигра - это паттерн.

Пример 2: Коробка передач  - это паттерн.

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

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

Шаблон проектирования / шаблон программирования / паттерн - это типичные способы решения часто возникающих задач в сфере разработки ПО.

 

ВАЖНО: 

Паттерн - это не готовое решение, которое можно откуда-то скопировать и вставить в Вашу программу. Это только общие принципы, которые надо уметь правильно применить.

Мне надо знать паттерны?

Ответ: "Да"

Потому что:

  • Паттерны очень часто применяются на практике. Конечно, для начинающих программистов понимание паттернов не всегда заходит легко. Так что наберитесь терпения и учим, учим, учим...
  • Паттерны часто спрашивают на собеседованиях.
  • И самое главное - паттерны предлагают Вам готовые решения. Они помогут Вам сохранить время и усилия, а качество программы повысится.

Откуда они взялись

Хотя сама идея паттернов далеко не новая, популярной она стала после выхода книги "Приёмы объектно-ориентированного проектирования. Паттерны проектирования". Это произошло в 1994 году. С тех пор мир  захватила "шаблономания" 🙂

Какие они бывают

Есть основные три категории паттернов:

  • Порождающие (Creational Design Patterns)

Эти шаблоны что-то создают. Например, "как создать объект, который нельзя изменить"? "Как создать класс, который будет создавать новые  объекты других классов?"? 

  • Структурные (Structural Design Patterns)

Отвечают за иерархию классов и интерфейсов. Например, "как заставить объекты с несовместимыми интерфейсами работа вместе"?

  • Поведенческие (Behavioral Design Patterns)

Помогает добиться нужного поведения от объектов. Например, "как сделать так, чтобы объекты одного класса следили за изменениями в других классах и реагировали на них"?

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

  • Имя
  • Задача, которую решает паттерн
  • Решение:
    • Структуры классов, составляющих решение;
    • Примера на одном из языков программирования;
  • Связь с другими паттернами

А конкретнее?

Существует 23 классических шаблона проектирования, с которых все и началось. В настоящий момент паттернов намного больше - минимум в 2-3 раза больше.

Здесь о каждом из них мы, конечно, говорить не будем - это много 🙂 Но мы расскажем об основных паттернах в будущих статьях.

Самыми-самыми "базовыми" шаблонами проектирования можно назвать следующие:

  • Singleton ("Одиночка")
  • Builder ("Строитель")
  • Factory ("Фабрика")
  • Wrapper ("Обертка")
  • Proxy ("Прокси")

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

Что следует знать

  • Одинаковые ли шаблоны для всех языков программирования?

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

  • 23 паттерна и все? Больше нет?

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

  • А я могу создать паттерн?

Да, конечно. Останется только всем о нем рассказать 🙂

Это все, что мы хотели Вам рассказать в данной статье.

Статьи, посвященные конкретным паттернам, Вы найдете по этим ссылочкам:


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


Зачем нужны паттерны ООП? / Habr

Эта статья — попытка ответить на вопрос 11-летнего олимпиадника: «Зачем нужны паттерны?» Ещё не отправил, выношу на общий суд и прошу любой критики. Цель — не дать исчерпывающий ответ, а вызвать новые вопросы.
Итак

Как учат программированию в школе? Вам дают формочки и учат делать куличики из песка. Это хорошо, надо ведь с чего-то начинать.

Но ты хочешь заняться более серьёзным делом. Например, построить дом. Из чего? Вас учили только из песка. Вам ничего не рассказывали о кирпичах — это не дело школы. (Скажу по секрету: они это не умеют.)

Хочешь строить дом? Подожди, давай научимся обжигать кирпичи. Или пойдём купим на рынке. Кирпичи — это и есть паттерны.

Почему это важно? Просто многие мои друзья (именно из разряда «олимпиадников») жестоко разочаровались в программировании, потому что они хотели строить зáмки из песка. Внешне это было классно! Например, мой друг написал сложнейшую логическую игру, но «на коленке», на анти-паттернах, как нас учили в школе…

«Анти-паттерн» — это то, как не надо проектировать программы.

А ещё мы с ним делали машинки на электромоторах. Мои машины всегда ездили быстрее, но я их делал «на коленке», из подручных материалов с изолентой. А он всегда пытался применять какие-то методы проектирования, стандартизировал «производственные процессы»… Его машины были медленнее. Но догадайся: кто из нас теперь стал конструктором (проектирует коробки передач)?

Вот что я наблюдаю: если ты сейчас научишься строить домá из песка (красивые!), машины на скотче (быстрые!), то потом переучиться практически невозможно. Мотивации не будет.

Вывод: если хочешь стать профессионалом, лучше начать строить домик из двух кирпичей, чем большущий зáмок из песка. Хотя замок проще.

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

Применение паттернов — это те знания, которые приходят только с опытом. Если ты уже начнёшь пытаться их применять, то сэкономишь несколько лет.

P.S. Хабру:

Вопрос «Зачем нужны паттерны… 11-летнему?!» предлагаю не обсуждать. Мне бы лет 15 назад рассказали хоть что-нибудь из проектирования! (При всём моём уважении к подходу «пусть набьёт шишки, а потом мы ему скажем, что есть паттерны»...)

Кстати, тенденция «ООП с пелёнок» не нова.

Обсуждения по теме

Для чего нужны шаблоны проектирования
Паттерны ООП в метафорах
Как два программиста хлеб пекли

Основы паттернов проектирования | C# и .NET

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

Последнее обновление: 31.10.2015

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

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

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

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

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

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

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

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

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

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

  • Строитель (Builder)

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

  • Прототип (Prototype)

  • Одиночка (Singleton)

Другая группа паттернов - структурные паттерны - рассматривает, как классы и объекты образуют более крупные структуры - более сложные по характеру классы и объекты. К таким шаблонам относятся:

  • Адаптер (Adapter)

  • Мост (Bridge)

  • Компоновщик (Composite)

  • Декоратор (Decorator)

  • Фасад (Facade)

  • Приспособленец (Flyweight)

  • Заместитель (Proxy)

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

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

  • Команда (Command)

  • Интерпретатор (Interpreter)

  • Итератор (Iterator)

  • Посредник (Mediator)

  • Хранитель (Memento)

  • Наблюдатель (Observer)

  • Состояние (State)

  • Стратегия (Strategy)

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

  • Посетитель (Visitor)

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

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

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

  • Интерпретатор (Interpreter)

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

  • Адаптер (Adapter)

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

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

  • Строитель (Builder)

  • Прототип (Prototype)

  • Одиночка (Singleton)

  • Мост (Bridge)

  • Компоновщик (Composite)

  • Декоратор (Decorator)

  • Фасад (Facade)

  • Приспособленец (Flyweight)

  • Заместитель (Proxy)

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

  • Команда (Command)

  • Итератор (Iterator)

  • Посредник (Mediator)

  • Хранитель (Memento)

  • Наблюдатель (Observer)

  • Состояние (State)

  • Стратегия (Strategy)

  • Посетитель (Visitor)

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

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

Как выбрать нужный паттерн?

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

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

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

Паттерны в объектно-ориентированном программировании

Главная > Курсы > Курсы для начинающих программистов | Курсы СУБД | Программирование и СУБД

Код курса: ПАТТЕРН

Путеводитель

Программирование и СУБД

Курсы Java

Этот курс в нашем Центре
успешно закончили
1066 человек!

Object-Oriented design patterns

09.02.07 Информационные системы и программирование

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

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

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

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

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



По окончании курса Вы будете уметь:
  • Распознавать и реализовывать шаблоны ООП при разработке программных продуктов

По окончании курса слушатели будут знать:

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

Продолжительность курса - 24 ак. ч.

Предварительная подготовка

Требуемая подготовка:

Опыт программирования с использованием объектно-ориентированных языков программирования (Java, C#, C++). Понимание принципов объектно-ориентированного подхода в программировании.

Получить консультацию о необходимой предварительной подготовке по курсу Вы можете у наших менеджеров: +7 (495) 232-32-16.

Наличие предварительной подготовки является залогом Вашего успешного обучения. Предварительная подготовка указывается в виде названия других курсов Центра (Обязательная предварительная подготовка). Вам следует прочитать программу указанного курса и самостоятельно оценить, есть ли у Вас знания и опыт, эквивалентные данной программе. Если Вы обладаете знаниями менее 85-90% рекомендуемого курса, то Вы обязательно должны получить предварительную подготовку. Только после этого Вы сможете качественно обучиться на выбранном курсе.

Рекомендуемые курсы по специальности

Чтобы стать профессионалом, мы рекомендуем Вам вместе с этим курсом изучить:

Программа курса

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

  • утренним группам с 8:30 до 10:00
  • дневным группам - по 1 ак.ч. до и после занятий (13.15-14.00, 17.10-17.55)

Ближайшие группы 

*Данная скидка действительна при заказе и оплате очного и онлайн обучения только сегодня. Запишитесь прямо сейчас со скидкой!

*Группа в формате открытого обучения.

*Данная скидка действительна при заказе и оплате очного и онлайн обучения только сегодня. Запишитесь прямо сейчас со скидкой!

*Группа в формате открытого обучения.

На данный момент групп нет

На данный момент групп нет

На данный момент групп нет

*Данная скидка действительна при заказе и оплате очного и онлайн обучения только сегодня. Запишитесь прямо сейчас со скидкой!

*Группа в формате открытого обучения.

с 10:00 до 17:00
Экономия до 15%
Вечер или Выходные
Стандартная цена
Онлайн
Экономия до 15%
Индивидуальное обучение Записаться
Частные лица 14 990 12 700 14 990 14 990 12 700 63 600 **
Организации 17 990 17 990 17 990
*Стоимость указана с учетом скидки. Для юридических лиц (организаций) указана минимальная цена, действующая при полной предоплате.
Центр предоставляет специальную услугу Индивидуального обучения. Длительность индивидуального обучения - минимум 4 академических часа. Стоимость обучения в Москве уточняйте у менеджера. При выездном индивидуальном обучении устанавливается надбавка: +40% от стоимости заказанных часов при выезде в пределах МКАД, +40% от стоимости заказанных часов и + 1% от стоимости заказанных часов за каждый километр удаления от МКАД при выезде в пределах Московской области. Стоимость выезда за пределы Московской области рассчитывается индивидуально менеджерами по работе с корпоративными клиентами.
**Указана минимальная цена за индивидуальное обучение. Число часов работы с преподавателем в 2 раза меньше, чем при обучении в группе. Если Вам для полного усвоения материала курса потребуется больше часов работы с преподавателем, то они оплачиваются дополнительно. В случае занятий по индивидуальной программе расчёт стоимости обучения и количества необходимых часов производится отдельно.

Документы об окончании

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

Удостоверение*

Свидетельство

Cертификат международного образца

*Для получения удостоверения вам необходимо предоставить копию диплома о высшем или среднем профессиональном образовании.

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

Все документы Центра

Актуальные новости

Учитесь в удобное Вам время! Теперь забронировать место в группе еще проще

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

Полный текст новости

Итоги Дня Карьеры: 5 вакансий, 20 соискателей и максимум нетворкинга

Две компании, пять вакансий и 20 соискателей - так прошел очередной День Карьеры в «Специалисте» 29 ноября. Соискатели и работодатели обменялись контактами и обсудили открытые позиции.

Полный текст новости

Все новости

Главная > Курсы > Курсы для начинающих программистов | Курсы СУБД | Программирование и СУБД

Что такое анти-паттерны? / Habr

Анти-паттерны — полная противоположность паттернам. Если паттерны проектирования —
это примеры практик хорошего программирования, то есть шаблоны решения определённых задач. То анти-паттерны — их полная противоположность, это — шаблоны ошибок, которые совершаются при решении различных задач. Частью практик хорошего программирования является именно избежание анти-паттернов. Не надо думать, что это такая непонятная теоретическая фигня — это конкретные проблемы, с которыми сталкивался практически каждый разработчик. Кто осведомлен, тот и вооружён! Рассмотрим же несколько расрпотранённых анти-паттернов в программировании.

Программирование копи-пастом (Copy and Paste Programming)


Данный анти-паттерн является, наверное, самым древним в программировании. Когда от программиста требуется написание двух схожих функций, самым «простым» решением является написание одной функции, её копирование и внесение некоторых изменений в копию. Какие проблемы это сулит? Во-первых, ухудшается переносимость кода — если потребуется подобный функционал в другом проекте, то надо будет искать все места, где программист накопипастил и переносить их по отдельности. Во-вторых, понижается качество кода — часто программист забывает вносить требуемые изменения в скопированный код. В-третьих, усложняется поддержка кода — так, как если в изначальном варианте был баг, который в будущем надо будет исправить, то этот баг попал во все то, что, опять-таки, накопипастил программист. Это приводит так же к возникновению различных множественных исправлений, которые будут возникать по мере нахождения бага в разных частях кода, для одного единственного бага. В-четвертых, code review значительно усложняется, так как кода становится больше, без видимой значительной выгоды и роста производительности труда. Главными причинами возникновения подобных ошибок являются — отсутствие мыслей про будущее разработки (программисты не продумывают свои действия), недостаток опыта (программисты берут готовые примеры и модифицируют, адаптируя под свои нужды). Решение же, является очень простым — создание общих решений и их использование. Об этом следует думать ещё при разработке решений небольших задач — возможно, что нам потребуется решить эту задачу где-нибудь ещё, или решить эту же задачу, но в другой интепретации.

«Брось, можно писать не только одну функцию!» или Спагетти-код (Spaghetti code)


Спагетти-код — слабо структурированная и плохо спроектированная система, запутанная и очень сложная для понимания. Такой код так же очень часто содержит в себе множество примеров анти-паттерна программирования копи-пастом. Подобный код в будущем не сможет разобрать даже его автор. В ООП спагетти-код может быть представлен в виде небольшого количества объектов с огромными, по размеру кода, методами. Причинами являются — разработка по принципу «Да ну, оно же работает! Целых пять тысяч строк!», малоэффективные code review, недостаток опыта в ООП разработке, удалённая работа отдельных программистов. Ипользовать спагетти-код повторно невозможно и нежелательно. Если в вашем проекте начинает возникать спагетти-код, а вам как раз надо расширить функционал, который он реализует — не ленитесь, рефакторьте спагетти полностью или напишите эту часть заново! Проиграв немного времени сейчас — вы получите огромный плюс в будущем. Или наоборот — проиграете, если оставите спагетти-код в проекте.

Золотой молоток (Golden hammer)


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

«Что за 42?» или Магические числа (Magic numbers)


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

«Что значит d:\proj\tests.dat?» или Жёсткое кодирование (Hard code)


Жёсткое кодирование — внедрение различных данных об окружении в реализацию. Например — различные пути к файлам, имена процессов, устройств и так далее. Этот анти-паттерн тесно связан с магическими числами, частенько они переплетаются. Захардкодить — жёстко прописать значение каких-либо данных в коде. Главная опасность, исходящая от этого анти-паттерна — непереносимость. В системе разработчика код будет исправно работать до перемещения или переименования файлов, изменения конфигурации устройств. На любой другой системе код может вовсе не заработать сразу же. Как правило, программист практически сразу забывает где и что он захардкодил, даже если делает это в целях отладки кода. Это делает выявление и локализацию данного анти-паттерна очень сложной. С этим надо бороться — оговорив запрет на жёсткое кодирование перед началом разработки и проводя тщательные code review.

Мягкое кодирование (Soft code)


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

Ненужная сложность (Accidental complexity)


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

Лодочный якорь (Boat anchor)


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

Изобретение велосипеда (Reinventing the wheel)


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

Изобретение одноколёсного велосипеда (Reinventing the square wheel)


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

«От твоего кода дурно пахнет» или Поток лавы (Lava flow)


На каком либо этапе разработки вы можете осознать, что некоторая часть кода очень давно не менялась и вообще недокументирована, или такому коду сопутствует комментарий вида "// Не знаю, как оно работает, но оно работает. Не удалять и не менять!". Если ничего не предпринимать, то такой код и останется в проекте. Но и рефакторить, разбирать его довольно сложно, особенно ели его автор уже не работает над проектом. Проще предусмотреть возникновение такого мёртвого кода, при разработке надо руководствоваться тем, что код в будущем возможно будет немного оптимизирован или дописан, но никак не переписан полностью. Главными причинами возникновения потоков лавы являются — написание больших частей проекта одним программистом, отсутствие code review, ошибки в проектировании архитектуры.

«А если i+1?» или Программирование перебором (Programming by permutation)


Многие начинающие программисты пытаются решать некоторые задачи методом перебора — не брутфорсом решения, а именно подбором параметров, порядка вызова функций и так далее. Все эти игры с +1, -1 к параметрам и подобные штучки устраняют только симптомы, и не дают понимания сути происходящего. А если программист не понимает происходящего, то он не сможет предусмотреть все варианты развития событий и обязательно о чём-то забудет. Он потратит время на подбор работающего для него решения и позднее потратит время для переделки этого решения. Все подобные подобранные решения вылазят боком и хорошо ещё — если в процессе разработки или отладки. К подобному ни в коем случае нельзя привыкать, достигая успеха на небольших задачках. Если программист не может решать задачи другим путём — он некомпетентен и ему не следует доверять разработку — вам же будет хуже.

«Как это вы передали строку вместо числа?!» или Слепая вера (Blind faith)


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

Бездумное комментирование


Результат «работы» данного анти-паттерна — большое количество лишних и неинформативных комментариев. Код не следует комментировать ради комментирования! Ведь комментарии — очень полезный инструмент, который должен помочь задокументировать нужную информацию для облегчения понимания кода, как автору в будущем, так и другим разработчикам. Ни в коем случае нельзя допускать диалога разработчиков в комментариях — лучше перенести данную функцию с комментариев на специализированные инструменты для code review, или на личное обсуждение.

Божественный объект (God Object)


«Мне нужен такой-то функционал. — Используй MegaCoreObject! — И ещё, мне нужен и… — Я же сказал, используй MegaCoreObject!»


Божественный объект — анти-паттерн, который довольно часто встречается у ООП разработчиков. Такой объект берет на себя слишком много функций и/или хранит в себе практически все данные. В итоге мы имеем непереносимый код, в котором, к тому же, сложно разобраться. Так же, подобный код довольно сложно поддерживать, учитывая, что вся система зависит практически только от него. Причинами являются — некомпетентность разработчика, взятие одним разработчиком большой части работы (особенно, когда размер работы «превышает» уровень опыта этого разработчика). Бороться с таким подходом надо — разбивать задачи на подзадачи, с возможностью решения этих подзадач различными разработчиками.
Анти-паттерны — главные враги разработчика, под их влияние программист частенько попадает из-за давление заказчика или проект-менеджера. Банальная нехватка времени и спешка сейчас запросто могут вылиться в огромные проблемы и неработоспособность системы в будущем. Следует помнить пару простых принципов — «Тише едешь — дальше будешь» и «Не подмажешь — не поедешь». Анти-паттерны надо не просто знать, надо знать их причины и методы борьбы, а ещё лучше — заранее предостерегать себя от их «использования». Программист не должен писать код так, чтобы его потом пришлось рефакторить, помните это ;)

Шпаргалка по MV-паттернам для проектирования веб-приложений / Habr


В Интернет можно найти множество различающихся реализаций и схем, уже набившего оскомину, паттерна MVC. В разных книгах я также встречал разные схемы. Это порождает некоторую путаницу и комментарии к моей предыдущей статье: "Реализация MVC паттерна на примере создания сайта-визитки на PHP" тому подтверждение. В поисках истины, я попытался расставить все по местам… перечитал некоторую литературу и статьи по паттернам проектирования и написал дополнение к упомянутой статье. Но решил запостить это дополнение, как отдельный топик в надежде на фидбэк. Под катом вы найдете несколько часто встречающихся схем MVC и MVP с описанием жизненного цикла приложения, а также описание менее популярных паттернов HMVC и MVVM. Разумеется, некоторые из перечисленных паттернов применимы не только к веб-приложениям, но в статье они рассматриваются именно в этом контексте.

MVC


Шаблон MVC (Модель-Вид-Контроллер или Модель-Состояние-Поведение) описывает простой способ построения структуры приложения, целью которого является отделение бизнес-логики от пользовательского интерфейса. В результате, приложение легче масштабируется, тестируется, сопровождается и конечно же реализуется.Некоторые умозаключения об MVC

Модель — содержит бизнес-логику приложения и включает методы выборки (это могут быть методы ORM), обработки (например, правила валидации) и предоставления конкретных данных, что зачастую делает ее очень толстой, что вполне нормально.
Модель не должна напрямую взаимодействовать с пользователем. Все переменные, относящиеся к запросу пользователя должны обрабатываться в контроллере.
Модель не должна генерировать HTML или другой код отображения, который может изменяться в зависимости от нужд пользователя. Такой код должен обрабатываться в видах.
Одна и та же модель, например: модель аутентификации пользователей может использоваться как в пользовательской, так и в административной части приложения. В таком случае можно вынести общий код в отдельный класс и наследоваться от него, определяя в наследниках специфичные для подприложений методы.
Вид — используется для задания внешнего отображения данных, полученных из контроллера и модели.
Виды cодержат HTML-разметку и небольшие вставки PHP-кода для обхода, форматирования и отображения данных.
Не должны напрямую обращаться к базе данных. Этим должны заниматься модели.
Не должны работать с данными, полученными из запроса пользователя. Эту задачу должен выполнять контроллер.
Может напрямую обращаться к свойствам и методам контроллера или моделей, для получения готовых к выводу данных.
Виды обычно разделяют на общий шаблон, содержащий разметку, общую для всех страниц (например, шапку и подвал) и части шаблона, которые используют для отображения данных выводимых из модели или отображения форм ввода данных.
Контроллер — связующее звено, соединяющее модели, виды и другие компоненты в рабочее приложение. Контроллер отвечает за обработку запросов пользователя. Контроллер не должен содержать SQL-запросов. Их лучше держать в моделях. Контроллер не должен содержать HTML и другой разметки. Её стоит выносить в виды.
В хорошо спроектированном MVC-приложении контроллеры обычно очень тонкие и содержат только несколько десятков строк кода. Чего, не скажешь о Stupid Fat Controllers (SFC) в CMS Joomla. Логика контроллера довольно типична и большая ее часть выносится в базовые классы.
Модели, наоборот, очень толстые и содержат большую часть кода, связанную с обработкой данных, т.к. структура данных и бизнес-логика, содержащаяся в них, обычно довольно специфична для конкретного приложения.


По запросу «MVC» в интернете можно найти множество различных схем, в которых очень легко запутаться. Попробуем расставить все по местам. Рассмотрим схему 1:

1. При заходе пользователя на веб-ресурс, скрипт инициализации создает экземпляр приложения и запускает его на выполнение.
2. Выполняется действие index фронт-контроллера, которое генерирует представление главной страницы.
3. Представление отображается пользователю.

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

4. После того, как приложение получит запрос от пользователя, создается экземпляр запрошенного контроллера и вызывается указанное действие.
5. В этом действии вызываются методы модели, изменяющие ее.
6. Генерируется представление (или же представление оповещается об обновлении модели).
7. Представление запрашивает данные для отображения.
8. Модель возвращает запрошенные данные.
9. Представление отображает результаты пользователю.

Встречается и такая схема — схема 2:

1. Контроллера получает следующий запрос от пользователя.
2. Далее в зависимости от внутренней логики:
      2a. Формируется представление какой-то страницы.
      2b. Либо, вызываются методы модели.
3. Модель уведомляет представление об изменениях.
4. Представление обновляется (если в цепочке была задействована модель) и отображается пользователю.

На некоторых схемах можно увидеть стрелку от представления к контроллеру. Рассмотрим этот случай — схема 3:

  1. Приложение получает еще один запрос от пользователя: создает экземпляр запрашиваемого контроллера и вызывает указанное действие.
  2. В действии генерируется представление содержащее некоторую форму ввода данных.
  3. Представление с формой отображается пользователю.
  4. После того как пользователь заполнит форму и нажмет на кнопку «Submit» вызывается тот же контроллер, который проверяет и обрабатывает полученные из формы данные и формирует другое представление или же обновляет текущее.

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

MVP


А теперь посмотрим на схему паттерна MVP (Model-View-Presenter) — схема 4:

  1. После того, как приложение получит запрос от пользователя, определяется запрошенный Presenter и действие. Приложение создает экземпляр этого Presenter'а и запускает метод действия.
  2. В методе действия могут содержаться вызовы модели, к примеру, считывающие информацию из базы данных.
  3. Модель возвращает данные.
  4. После этого действие формирует представление, в которое передаются данные полученные из модели.
  5. Сформированное представление отображается пользователю.

Помимо MVP существуют и другие, производные от MVC, паттерны, например MVVM и HMVC.

HMVC


Реализация паттерна HMVC (Hierarchical Model View Controller — Иерарархические Модель-Контроллер-Вид) используется в веб-фреймворке Kohana. Рассмотрим в чем же ключевое отличие от MVC — схема 5:


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

MVVM


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

Когда появился Ajax и богатые клиент-сайд приложения (RIA), оказалось, что MVC не очень хорошо подходит для работы с областями страницы или приложения, что привело к несколько иным моделям: MVP (Model View Presenter) и затем к MVVM (Model View ViewModel). Если c паттернами MVC и MVP большинство более-менее знакомо, то о последнем слышали очень немногие.

Первоначально MVVM был описан для Silverlight и имеет преимущества для сложных интерфейсов с определенной логикой, которая отличается от логики приложения. MVVM отличается более «тесной» связью между Моделью и Представлением посредством слоя Представление-Модель, который синхронизирует данные как при событии на стороне Модели, так и на стороне Представления.

В MVC логика зашита в Модели, ее можно также помещать в Контроллер, но это справедливо подвергается критике (Stupid Fat Controller). В MVVM, напротив, логика помещается в «промежуточный» слой ViewModel. Рассмотрим схему MVVM — схема 6:

Вы определяете видимую область экрана и задаете самые общие данные о нем, не зная, какое содержание будет показываться во время выполнения. Для HTML схема MVVM особо удачна благодаря DOM, который, как известно, вполне может вмещать данные. Поэтому MVVM была успешна реализована во фреймворке KnockOut.JS. Изначально все просто. Есть Модель данных, предоставленная сервером. Есть Представление в виде DOM, в виде разметки. А есть Представление-Модель (Вид Модели, если хотите), которая описывает изменение Представления, связывает Модель и Представление, причем синхронизует эту связь.

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

Заключение


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

Полезные ссылки


Чуть более подробнее о MVVM, MVP и MVC применительно к клиент-сайд приложениям…

Другие паттерны:

IoC & DI

АОП

Подборка в этом спойлере не совсем по сабжу… я сделал ее скорее для себя, т.к. в ходе написании статьи веб-серфинг остановился именно на этих ссылках.

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

Что такое паттерны

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

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

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

Классификация паттернов

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

Паттерны делятся на следующие категории:

  • Архитектурные паттерны
  • Паттерны проектирования
  • Идиомы

Архитектурные паттерны, являясь наиболее высокоуровневыми паттернами, описывают структурную схему программной системы в целом. В данной схеме указываются отдельные функциональные составляющие системы, называемые подсистемами, а также взаимоотношения между ними. Примером архитектурного паттерна является хорошо известная программная парадигма "модель-представление-контроллер" (model-view-controller - MVC). В свою очередь, подсистемы могут состоять из архитектурных единиц уровнем ниже.

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

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

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

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

  • Абстрактная фабрика (Abstract factory) - класс, который представляет собой интерфейс для создания компонентов системы.
  • Фабричный метод (Factory method) - определяет интерфейс для создания объекта, но оставляет подклассам решение о том, какой класс инстанцировать.
  • Прототип (Prototype) - определяет интерфейс создания объекта через клонирование другого объекта вместо создания через конструктор.
  • Строитель (Builder) - класс, который представляет собой интерфейс для создания сложного объекта.
  • Одиночка (Singleton) - класс, который может иметь только один экземпляр.
  • Отложенная инициализация (Lazy initialization) - объект, инициализируемый во время первого обращения к нему.

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

  • Адаптер (Adapter) - объект, обеспечивающий взаимодействие двух других объектов, один из которых использует, а другой предоставляет несовместимый с первым интерфейс.
  • Компоновщик (Composite) - объект, который объединяет в себе объекты, подобные ему самому.
  • Декоратор или Обёртка (Decorator) - класс, расширяющий функциональность другого класса без использования наследования.
  • Фасад (Facade) - объект, который абстрагирует работу с несколькими классами, объединяя их в единое целое.
  • Единая точка входа (Front Controller) - обеспечивает унифицированный интерфейс для интерфейсов в подсистеме. Front Controller определяет высокоуровневый интерфейс, упрощающий использование подсистемы.
  • Заместитель (Proxy) - объект, который является посредником между двумя другими объектами, и который реализует/ограничивает доступ к объекту, к которому обращаются через него.

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

  • Команда, Экшен, Транзакция (Command) - представляет действие. Объект команды заключает в себе само действие и его параметры.
  • Стратегия (Strategy) - предназначен для определения семейства алгоритмов, инкапсуляции каждого из них и обеспечения их взаимозаменяемости.
  • Шаблонный метод (Template method) - определяет основу алгоритма и позволяет наследникам переопределять некоторые шаги алгоритма, не изменяя его структуру в целом.
  • Наблюдатель, Слушатель (Observer) - определяет зависимость типа «один ко многим» между объектами таким образом, что при изменении состояния одного объекта все зависящие от него оповещаются об этом событии.
  • Цепочка обязанностей (Chain of responsibility) - предназначен для организации в системе уровней ответственности.

Паттерны проектирования без ООП / Habr

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

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

Наблюдатель

Нужно обеспечить возможность каким-то объектам подписываться на сообщения, а каким-то эти сообщения отсылать.
Реализуется словарём, который и представляет собой «почту». Ключами будут названия рассылок, а значениями списки подписчиков.
from collections import defaultdict mailing_list = defaultdict(list) def subscribe(mailbox, subscriber): # Подписывает функцию subscriber на рассылку с именем mailbox mailing_list[mailbox].append(subscriber) def notify(mailbox, *args, **kwargs): # Вызывает подписчиков рассылки mailbox, передавая им параметры for sub in mailing_list[mailbox]: sub(*args, **kwargs) 

Теперь можно любые функции подписывать на рассылки. Главное, чтобы интерфейс функций входящих в одну и ту же группу рассылки, был совместим.
def fun(insert): print 'FUN %s' % insert def bar(insert): print 'BAR %s' % insert 

Подписываем наши функции на рассылки:

>>> subscribe('insertors', fun) >>> subscribe('insertors', bar) >>> subscribe('bars', bar) 

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

>>> notify('insertors', insert=123) FUN 123 BAR 123 >>> notify('bars', 456) BAR 456 
Шаблонный метод

Нужно обозначить каркас алгоритма и дать возможность пользователям переопределять определенные шаги в нём.
Функции высшего порядка, такие как map, filter, reduce по сути и являются такими шаблонами. Но давайте посмотрим, как можно провернуть такое же самому.
def approved_action(checker, action, obj): # Шаблон, который выполняет над объектом obj действие action, # если проверка checker дает положительный результат if checker(obj): action(obj) import os def remove_file(filename): approved_action(os.path.exists, os.remove, filename) import shutil def remove_dir(dirname): approved_action(os.path.exists, shutil.rmtree, dirname) 

Имеем функции удаления файла и папки, проверяющие предварительно, есть ли нам чего удалять.
Если вызов «шаблона» напрямую кажется противоречащим паттерну, можно определять функции с помощью каррирования. Ну и ввести до кучи возможность «переопределения» не всех частей алгоритма.
def approved_action(obj, checker=lambda x: True, action=lambda x: None): if checker(obj): action(obj) from functools import partial remove_file = partial(approved_action, checker=os.path.exists, action=os.remove) remove_dir = partial(approved_action, checker=os.path.exists, action=shutil.rmtree) import sys printer = partial(approved_action, action=sys.stdout.write) 
Состояние

Нужно обеспечить разное поведение объекта в зависимости от его состояния.
Давайте представим, что нам нужно описать процесс выполнения заявки, который может потребовать несколько циклов согласований.
from random import randint # Функции, выполняющие работу в каждом из состояний. # Аргументом ко всем является обрабатываемая заявка # Вызовы randint эмулируют логику, принимающую какие-то решения в зависимости от внешних обстоятельств def start(claim): print u'заявка подана' claim['state'] = 'analyze' def analyze(claim): print u'анализ заявки' if randint(0, 2) == 2: print u'заявка принята к исполнению' claim['state'] = 'processing' else: print u'требуется уточнение' claim['state'] = 'clarify' def processing(claim): print u'проведены работы по заявке' claim['state'] = 'close' def clarify(claim): if randint(0, 4) == 4: print u'пользователь отказался от заявки' claim['state'] = 'close' else: print u'уточнение дано' claim['state'] = 'analyze' def close(claim): print u'заявка закрыта' claim['state'] = None # Определение конечного автомата. Какие функции в каком состоянии вызывать state = {'start': start, 'analyze': analyze, 'processing': processing, 'clarify': clarify, 'close': close} # Запуск заявки в работу def run_claim(): claim = {'state': 'start'} # Новая заявка while claim['state'] is not None: # Крутим машину, пока заявка не закроется fun = state[claim['state']] # определяем запускаемую функцию fun(claim) 

Как видим, основную часть кода занимает «бизнес-логика», а не оверхед на применение паттерна. Автомат легко расширять и изменять, просто добавляя/заменяя функции в словаре state.

Запустим пару раз, чтобы убедиться в работоспособности:

>>> run_claim() заявка подана анализ заявки требуется уточнение уточнение дано анализ заявки заявка принята к исполнению проведены работы по заявке заявка закрыта >>> run_claim() заявка подана анализ заявки требуется уточнение пользователь отказался от заявки заявка закрыта 
Команда

Задача – организовать «обратный вызов». То есть, чтобы вызываемый объект мог из своего кода обратиться к вызывающему.
Этот паттерн видимо возник из-за ограничений статичных языков. Функциональщики бы его даже звания паттерна не удостоили. Есть функция – пожалуйста, передавай её куда хочешь, сохраняй, вызывай.
def foo(arg1, arg2): # наша команда print 'FOO %s, %s' (arg1, arg2) def bar(cmd, arg2): # Приемник команды. Ничего не знает о функции foo... print 'BAR %s' % arg2 cmd(arg2 * 2) # ...но вызывает её 

В исходных задачах паттерна Команда есть и возможность передавать некоторые параметры объекту-команде заранее. В зависимости от удобства, решается либо каррированием…

>>> from functools import partial >>> bar(partial(foo, 1), 2) BAR 2 FOO 1, 4 

…либо заворачиванием в lambda
>>> bar(lambda x: foo(x, 5), 100) BAR 100 FOO 200, 5 
Общий вывод

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

Паттерны проектирования для человеков. / Habr

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

Ликбез:
Инкапсуляция — сокрытие сущности объекта за интерфейсом (нам пох как у нас хранится картинка, нам нада только уметь выводить еще на экран, ресайзить, поворачивать...)
Экземпляр класса — объект :)

Краткое введение:
Паттерны делятся на 3 основные группы:
1. Порождающие — паттерны отвечающие за создание объектов;
2. Структурные — определяют структуру представления классов/объектов;
3. Паттерны поведения — паттерны для инкапсуляции (сокрытия) действий над объектами.

1. Порождающие


Abstract Factory — создает объекты похожих классов.
У нас есть абстрактный класс и наследники, создается абстрактная фабрика и конкретные фабрики для наследников. Необходим для того что бы отделить методику создания объектов разных классов. Классы должны быть связаны.
Пример на C#
На русском с рисунками

Builder — отделяет создание объекта и его представления.
Позволяет при вызове одного и того же метода создания, получить разные результаты.
Пример на C#
На русском с рисунками

Singleton — гарантирует наличие одного экземпляра класса.
Используется, если в системе нужно гарантировать наличие одного экземпляра класса (объекта). Например, в системе может быть только один бланк учета черной бухгалтерии. Это аналог глобальной переменной, но намного круче.
Пример на C#
На русском с рисунками

2. Структурные


Adapter — адаптирует :) интерфейс одного класса к другому.
Допустим есть два класса, и мы имеем доступ только к интерфейсам (код менять низя). И нужно наладить взаимодействие. Тогда применяется паттерн. Он берет интерфейс класса А и его методы преобразовывает для класса В.
Пример: есть класс для работы с комплексными числами, у него методы ToCompl(int i) и есть другой класс который знает про комплексные числа но думает что там метод называется ConvertToComplex(int i), делаем адаптер для первого класса, который будет иметь метод ConvertToComplex, а в нем вызывать ToCompl (пример тупой, оперирует только названиями, а в реале там можно заменять все, например вызывать не 1 метод, а 15)
Пример на C#
На русском с рисунками

Composite — позволяет создать один простой интерфейс для кучи похожих классов.
Допустим есть разные геометрические фигуры(Line, Circle), наследуем их от класса Figure у которого есть метод Draw и тем самым мы обеспечим простой вызов прорисовки для всех наследников.
Пример на C#
На русском с рисунками

Decorator Динамическое добавление функционала для класса.
Например есть класс фотка, и нам нада навесить рамку, делаем класс который будет выводит фотку (метод класса Фотка) и потом выводить рамку (уже своими методами)
Пример на C#
На русском с рисунками

Proxy — заменяет класс на себя :)
Получается что для всей системы прокси выглядит как необходимый класс, но не является таковым.
Например есть большой объект (пдф документ) и нам нада его отобразить на экране. Грузить весь нельзя (в память не влезет). Поэтому делаем прокси который будет постранично грузить и выводить, но выглядеть он будет как настоящий документ.
Пример на C#
На русском с рисунками

3. Паттерны поведения


Command — инкапсулирует действие в объект.
Например есть менюха которая должна выводить сообщение. Мы не просто в обработчике меню пишем вывод, а делаем класс который это делает. Дерево таких классов позволяет организовать такую штуку как «Отменить/пофторить», фактически мы можем сохранять наши действия.
Пример на C#
На русском с рисунками

Iterator — позволяет обходить коллекцию объектов. Например есть вектор (массив) и мы вместо [] пишем методы Next, Previos. Таким образом мы не привязались к массив и в дальнейшем можем заменить его на другую структуру.
Пример на C#
На немецком с рисунками

Memento — позволяет сохранить состояние объекта. Например в фотошопе у нас есть отмена команд, мы применили ацкий фильтр который всю фотку испоганил, обратной ф-ции этого фльтра нет (паттерн Команда не проканает), мы перед применением фильтра, тупо сохраняем фотку и потом можем ее восстановить.
Пример на C#
На украинсокм с рисунками

Observer — налаживает взаимодействие объектов. Например есть формочка, мы нажимаем кнопочку и в текстовом поле выводится «42», можно написать тупо в обработчике кнопки типа изменить поле, но это не тру. Тру: создаем объект Наблюдатель(обычно это сингелтон) и в кнопочке вызываем метод в этом Наблюдателе, а он уже предеает это сообщение всем текстовым полям (их же может стать больше :)
Пример на C#
На русском с рисунками

Mediator — тоже самое что и Observer, но там отношение «Много к многим».
Например у нас не только кнопочка, а еще и менюшка есть.
Пример на C#
На украинсокм с рисунками

State — позволяет подменять класс его наследниками.
Например, есть заявка, она или обработана или необработана (третьего не дано). Мы для этих двух состояний делаем классы и наследуем от абстрактного класса СостояниеЗаявки, у которого есть метод ИзменитьСостояние. В реализации этого метода мы будем заменять текущее состояние на нужный нам объект (Обработано, Необработано) эти состояния обычно сингилтоны.
Пример на C#
На украинсокм с рисунками

Strategy — позволяет инкапсулировать алгоритмы.
Например нам нужно сортировать массив и нам пофигу каким методом (пузырьком, быстрая...) поэтому создаем класс, а от него наследников — конкретные алгоритмы, и уже там — методы Отсортировать, а у же в методах конкретных сортировок реализуем их. Это позволяет что бы другие классы вобще не знали как и что мы сортируем.
Пример на C#
На русском с рисунками

Visitor — позволяет навесить функционал на уже готовый класс.
Например, есть работник, у него есть черная и белая зарплата. Считается по разному. Класс работника менять низя. Делаем посетителя, у которого будет два метода ПосчитатьРеально и ПосчитатьДляНалоговиков. Он будет брать объект Работник, вытаскивать из него ставку и по разному считать.
Пример на C#
На итальянском с рисунками

upd: Технический редактор — Антон.


Смотрите также