Здравствуйте!
— Не хотите ли войти
Оглавление

Про стандартные паттерны в программировании

8 февраля 2010
Уровень сложности: для начинающих

Аннотация

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

Зачем нужны паттерны?

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

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

Зачем их использовать? «Я сам все придумаю…» — подумаете вы и будете правы. Придумаете. Но потом въедете в какой-нибудь крайний случай и придется все переделывать. Или дорабатывать. И так не один раз. А паттерны разработаны уже по следам таких исправлений. В них учтены проблемы, аккуратно рассмотрены разные варианты неприятностей… Вы же не изобретаете чайник, просто идете и выбираете подходящий. И в программировании можно делать также, воспользоваться опытом и картой граблей на пути решения проблем, которые созданы предыдущими поколениями.

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

В общем, паттерны полезны всем. Но разработчикам мака — вдвойне. Так уж получилось, что мак и айфон не просто дают возможность использования паттернов, но предлагают использовать свои. И делают это непрерывно и очень настойчиво. Поэтому лучше один раз разобраться и потом уже разговаривать с API на нормальном языке, чем каждый раз вспоминать, что же тут оно сказало. Рассмотрим для начала два самых важных паттерна: Model-View-Controller и Delegate. Человеческих названий им не придумали, поэтому буду обращаться к ним как получится, например, MVC и Делегат. Или еще как-нибудь, думаю, что всегда будет понятно. Итак, начнем.

MVC

Этом паттерном пронизан весь интерфейс. Даже, наверное, интерфейс основывается на нем. И, в общем, не только в Mac OS X. Состоит этот паттерн, как можно догадаться из названия, из трех частей. Модель (структура данных), представление (вид), контроллер (управляющий объект). Почему именно так и почему этим все пользуются? Дело в том, что у разработчиков библиотек создания пользовательского интерфейса одинакове проблемы. Нужно предоставить набор компонентов, которые рисуются стандартным образом, но реагируют на действия пользователя нужным программисту способом (каждый раз своим), и берут данные из нужных программисту источников. Про представление, причем, разработчику библиотеки (хм, слово «библиотекарь» приобретает новый смысл) известно, ведь обычно это стандартный вид компонентов системы. А вот с остальным — беда. Хотя, если вспомнить про скины и виндовые темы, то беда и с представлением. Как же сделать так, чтобы и максимально облегчить работу программисту, и дать возможность переделывать все что нужно? Тут и появляется MVC.

Этот паттерн очень грамотно разбивает компонент на три части:

  • Модель (Model)
  • Представленние (View)
  • Контроллер (Controller)

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

Модель хранит данные и выдает их остальным частям паттерна. Самый интересный, пожалуй, вариант использования модели — когда данные берутся из базы данных и отображаются в таблице. Тогда модель занимается выполнением SQL-запросов, сортировкой, фильтрацией строк. Особенно очевидна выгода такого решения, если вдруг поменялся источник данных. Другая СУБД, или просто переключение между тестовым набором данных в XML и живой БД. Поменяли модель — и все. Попробуйте сравнить затраты на изменение кода со случаем, если, скажем, весь код, связанный с компонентом живет в одном классе.

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

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

Delegate

Второй рассматриваемый паттерн — делегат. Пока не было объектов, похожими вещами занимался обратный вызов, или callback, delegate — в некотором смысле его развитие. В чем же его суть? Часто одна часть системы знает, когда произойдет событие (системная часть контроллера из MVC знает, когда пользователь нажал на кнопку), а другая часть — в курсе, что с этим делать (конкретный обработчик событий в вашем коде). Например, написать слово на экране. В этом случае класс, который в курсе, когда что-то произойдет, дает возможность сохранить объект и селектор в специальные поля. И в случае свершения сообщения — он смотрит, есть ли в этих полях что-то. Если есть, тогда он передает сообщение по указанному адресу.

В OS X есть два основных шаблона использования делегатов. В первом случае устанавливается и объект делегата и селектор, объект обычно называется target, а селектор action. Второй вариант использования предполагает установку только поля delegate. В таком случае реализуемые методы должны называться строго определенным образом, а зачастую, вообще, класс должен реализовывать определенный протокол.

Примеры

Примеров именно этих паттернов множество. Делегат, например, появляется сразу после создания приложения в виде ВашеПриложениеAppDelegate. Этот класс может реализовывать всякие разные методы. Его мы указываем при конструировании UIApplication, где и происходит связывание его с приложением, после чего приложение посылает делегату сообщения в разные моменты времени, при старте приложения или завершении его работы. Также делегаты есть у сложных компонентов, например, UITableView, где их даже два, сам делегат, реагирующий на тыки пользователя, и источник данных (DataSource).

Более простые компоненты обычно довольствуются вариантом установки target и action. Так, например, делают всякие кнопки.

MVC также появляется при создании простейшего проекта. При создании View-based приложения создается наследник UIViewController. Это как раз кусок MVC, не трудно догадаться, какой. Вид обычно рисуется в интерфейс-билдере и привязывается к контроллеру при помощи биндинга (binding, «протягивание» мышкой в Interface Builder). Модель в простом случае не выделяется. Например, если у вас кнопка или статический текст, то модель — это просто строка, и она прописывается при создании компонента. В более сложном случае, как например, в том же UITable, DataSource, который я назвал делегатом — является не просто делегатом, а делегатом модели списка. То есть разработчиками ОС написана стандартная модель, а вам предоставляют возможность заполнить ее данными, реализовав несколько методов.

© 2009-2010, ООО «Инру»
Вход
Имя пользователя:
Пароль:
Или…
Twi
Отмена
Войти
Восстановить забытый пароль…