Как отделить мух от котлет?

Рано или поздно любой flex-разработчик понимает, что нужно что-то сделать с собственным «винегретом» в коде, состоящим из mxml-разметки вперемешку с inline-кодом. А, собственно, что с ним не так? Если кратко, то:

  • код трудночитаем, из-за постоянного перехода внутри одного файла от as3 кода к mxml разметке и обратно;
  • сильная связанность (нет возможности легко заменить разметку или реализацию);
  • низкая переиспользуемость кода (трудно перенести код/разметку в другой проект);
  • отсутствует возможность разделить обязанности между разработчиком и дизайнером (кто-нибудь помнит/пользовался Flash Catalyst?, ах да: Development and sales ended on April 23, 2012);
  • сильно разросшийся размер файла;
  • и так далее.


Почему же так происходит? Отчасти в этом виновата сама Adobe, которая не удосужилась привить нужные навыки будущим разработчикам. Официальный хелп пестрит примерами наподобие этого (это всего лишь примеры, но все же):

 

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

Не будем о грустном. Так как же можно отделить просо от гречки? Если хорошо поискать, то Adobe предлагает следующие варианты:

  • использовать <fx:Script> блок. Собственно, от его использования мы и пытаемся избавиться;
  • инлайн обработчики событий:

 

  • в отдельном as файле: <fx:Script source=»includes/Sample3Script.as»/>.

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

Описывание кода в отдельном as файле ни к чему, кроме головной боли, не ведет. Как минимум, код в пустом (безо всяких package, class и тд) файле выглядит странно, запутывает и приводит в уныние, наверное, все современные IDE. Кто-нибудь сейчас так пишет? Получается, название статьи расходится с её содержанием. Зачем она нужна непонятно (см. абзац «Почему так происходит»).

Вот мы все ругаем Adobe за Flex. Так ведь да, в один прекрасный момент она сама это поняла и переписала часть фреймворка, как надо. Ввела новый жизненный цикл компонентов и отделила логику/поведение компонентов от их внешнего вида и увеличила цифру у фреймворка аж до 4.00. Можно даже почитать, как правильно готовить такие компоненты. Переписать все компоненты сил не хватило, теперь этим занимается Apache Foundation.

Что же делать? И как быть? Наверное, многие уже поняли, к чему я клоню, и вспомнили о старом, добром CodeBehind-е.  Идея этого архитектурного паттерна проста: всю бизнес-логику пишем на чистом as3 (базовый класс), а расположение и внешний вид контролов, описываем, используя mxml-разметку. Все контролы, которые будут использоваться в коде, должны иметь id и быть описаны в базовом классе как публичные переменные с соответствующим типом. Звучит страшно, но на самом деле все просто. Рассмотрим пример:

В приведенном примере мы видим два варианта подписки на событие клика по кнопке. Стоп-кнопку мы подписываем на клик mxml файле. Для этого необходимо, чтобы обработчик события был виден, т.е. был либо protected либо public. Старт-кнопку мы подписываем в createChildren, сразу после того, как она создастся. Оба варианта приемлемы. Вариант с подпиской в разметке, как нам кажется, короче, но не так универсален. Если нам нужно будет создать еще один вариант разметки, нам придется еще раз подписывать кнопку на это событие, что избыточно и легко может привести к ошибке, если мы забудем это сделать. С другой стороны, если нам нужно подписаться на это событие не сразу, или подписать вообще другой компонент (который также может послать это событие), то сделать это без изменения as3 кода не получится. А так как именно эту проблему мы и решаем, то вариант с подпиской на событие в разметке в данном случае подходит лучше. Используем тот вариант, который решает нашу задачу лучше.

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

  • создание конструктора класса;
  • возможность тестировать логику приложения отдельно от её представления;
  • возможность наследоваться от базовой логики, без необходимости нести с собой mxml-мусор.

Но, как и у любого другого шаблона, у CodeBehind есть не только плюсы, но и минусы:

  • увеличилось количество набираемого кода;
  • увеличилось количество файлов/классов для редактирования (что приводит к частому переключению между вкладками в IDE);
  • использование наследования вместо композиции, что ведет к увеличению иерархии наследования;
  • необходимость в предоставлении ссылок-заглушек при тестировании базовых классов;
  • возможно частичное нарушение инкапсуляции и наследования.

Другим вариантом реализации отделения логики от разметки является приём, называемый CodeFront (или code in front). Идея его (вы наверное и сами догадались) так же проста и кристальна, как и в случае с CodeBehind, и заключается в том, что сначала мы реализуем расположение компонентов, и только потом наполняем их жизнью (добавляем логику). Пример:

Используя CodeFront, нам больше нет необходимости описывать все необходимые переменные в классе, чтобы использовать их в логике. Так как мы наследуемся от mxml-разметки, то компилятор делает это за нас. Но теперь мы лишены возможности назначить обработчик события inline-внутри mxml-разметки, так как описан он будет только в наследнике. Также нет возможности полностью заменить layout получившегося компонента, по понятным причинам. Да и перенести логику в другой проект без layout-а теперь не получится. Возможно, поэтому этот вариант гораздо менее популярен, чем CodeBehind.

Заключение.

CodeBehind/CodeFront — архитектурный прием, который позволяет относительно легко сделать код чистым и структуированным, что  легко дает возможность модифицировать его в будущем. Хотя поначалу довольно непросто привыкнуть писать код так, и это сильно раздражает. Даже кажется, что мы делаем слишком много дополнительной работы. Но, как говорится, стоит только начать, а уж когда втянетесь… Становится легче абстрагировать логику от разметки. Гораздо легче наследоваться от чистых AS3 классов, нежели от MXML классов с необходимостью изменять layout. Попробуйте один из перечисленных приемов в своем проекте. И обязательно оставляйте комментарии о своем положительном/отрицательном использовании перечисленных техник.

Почитать:

Code Behind
Code behind in Flex and WPF
Flex and WPF: A comparison – Part 2b
Code-Behind and Flex 2.0 (Partial Classes)
Building components by using code behind
Creating components and enforcing separation of concerns with Flex
Best Practice: Code Behind versus MXML Script Blocks versus View Helper

Добавить комментарий