`

СПЕЦИАЛЬНЫЕ
ПАРТНЕРЫ
ПРОЕКТА

Архив номеров

Как изменилось финансирование ИТ-направления в вашей организации?

Best CIO

Определение наиболее профессиональных ИТ-управленцев, лидеров и экспертов в своих отраслях

Человек года

Кто внес наибольший вклад в развитие украинского ИТ-рынка.

Продукт года

Награды «Продукт года» еженедельника «Компьютерное обозрение» за наиболее выдающиеся ИТ-товары

 

Модель - представление - контроллер: не все так просто

Статья опубликована в №47 (615) от 11 декабря

+11
голос

Многие знают об архитектуре модель-представление-контроллер (Model-View-Controller, MVC) и пытаются применять ее в своей практике. Действительно, очень заманчиво разделить приложение на три независимых компонента и тем самым упростить каждый из них. Однако произойдет это не автоматически. Недостаточно лишь спроектировать новое приложение в соответствии с требованиями MVC – надо также учесть множество деталей, которые, на первый взгляд, покажутся второстепенными, но существенно повлияют на процесс разработки и качество создаваемого продукта. Одним словом, чтобы облегчить себе жизнь, сначала надо изрядно потрудиться.

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

Стремление к независимости и суровая реальность

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

Представление и контроллер: им не жить друг без друга

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

С другой стороны, в реальных приложениях за формирование контроллера часто отвечает представление. Более того, использование некоторых технологий программирования и вовсе делает невозможным другие решения. Например, чтобы создать контроллер в MVC-приложении на языке Java, надо зарегистрировать класс в качестве обработчика события. Поэтому о независимости речь идти попросту не может. Представление и контроллер буквально «прорастают» друг в друга.

Модели бывают разные

Модель - представление - контроллер не все так просто
Если представление обрабатывает информацию, оно само может быть реализовано по схеме MVC

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

Запрет на обновление, но не на чтение

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

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

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

Образы разработки упрощают жизнь

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

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

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

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

«Лишний» модуль

Казалось бы, распределение ролей между элементами триады MVC уже давно устоялось. Данная архитектура хорошо зарекомендовала себя на практике. Однако есть операции, которые не то чтобы серьезно нарушают сложившиеся традиции, но все же заставляют разработчика немного призадуматься. Речь идет о сортировке и фильтрации. Предположим, что пользователя MVC-приложения интересует, с каких узлов осуществлялся доступ к Web-серверу, причем набор результатов надо отсортировать в порядке убывания активности, т. е. узлы, с которых поступило наибольшее число обращений, должны быть представлены первыми. Если бы модель включала базу данных, никаких проблем бы не возникло; средства сортировки – неотъемлемая часть любой СУБД, и пользоваться ими чрезвычайно просто. В данном же случае моделью является обычный файл протокола, содержащий информацию в текстовом формате, и программы синтаксического разбора. Очевидно, что для решения задачи придется написать модуль сортировки. Но какому компоненту он должен принадлежать: модели или представлению? С одной стороны, обработка данных – функция модели, с другой – вполне вероятно, что со временем потребуется реализовать иные способы сортировки, например по регионам, и при этом убрать из результатов узлы, занесенные в «черный список», т. е. понадобится еще и модуль фильтрации. В результате модель непомерно разрастется. Выходит, что в рамках «классической» архитектуры MVC оба способа размещения модуля сортировки как минимум неудобны. А поскольку подобные задачи возникают очень часто, приходится подумать о доработке схемы.

И в представлении может быть модель

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

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

MPVC

Предположим, что модуль сортировки, доставивший выше столько хлопот, по каким-то причинам неуместен в представлении. На первый взгляд, ничего не остается, кроме как поместить его в состав модели. Но ведь и ее чрезмерного усложнения допускать не хочется. А что, если разместить модуль не в самой модели, а «рядом» с ней? Поступив так, мы получим разновидность архитектуры MVC – MPVC (model-pipe-view-controller – модель-канал-представление-контроллер). Новый элемент, называемый каналом, располагается «на пути» от модели к представлению. В нашем случае на него возлагается обязанность сортировки данных, полученных от модели, в других приложениях он может выполнять иные обязанности. (Вероятно, термин «канал» не совсем точно отражает назначение этого элемента, уместнее было бы назвать его «преобразователем», но давать названия технологиям – прерогатива их создателей.) Теперь, если потребуется произвести сортировку другого типа или выполнить фильтрацию, достаточно разработать соответствующий канал. Более того, модули, выполняющие различные преобразования, можно располагать в цепочку друг за другом, реализуя обработку информации любой сложности. Канал может работать с моделями любого типа, но лучше всего – с активными. В этом случае контроллеру в ответ на запрос пользователя достаточно лишь скомпоновать требуемым образом модули преобразования, после чего он может действовать так же, как и в обычной схеме MVC. Дополнительная обработка информации произойдет автоматически.

А может воздержаться?

Оказывается, MVC – это вовсе не тривиально. Чтобы грамотно написать приложение данной архитектуры, надо серьезно поработать. Поэтому сам собой напрашивается вопрос: а резонно ли применять MVC? Ведь наверняка среди продуктов, пользующихся успехом на рынке, есть и реализованные на совершенно других принципах. К тому же во многих системах достаточно сложно разделить обработку данных и их представление. Конечно, выбор архитектуры – дело программиста. Ему решать, как воплощать свои замыслы, ему же пожинать плоды удачного подхода или расплачиваться за ошибки. Но, принимая решение, способное повлиять на судьбу проекта, стоит вспомнить мнение Мартина Фаулера (Martin Fowler), признанного авторитета в области архитектуры программного обеспечения. По его словам, схема MVC уместна в любом приложении с графическим пользовательским интерфейсом. Единственным исключением, считает он, являются очень простые программы, в которых алгоритмы обработки данных тривиальны. «Без MVC, – говорит Фаулер, – можно обойтись разве что в статических HTML-страницах, никогда не изменяющихся и не выполняющих никаких действий, кроме собственно отображения информации. В остальных же случаях MVC придется весьма кстати».

Образы разработки, используемые в MVC

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

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

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

+11
голос

Напечатать Отправить другу

Читайте также

 
 
IDC
Реклама

  •  Home  •  Рынок  •  ИТ-директор  •  CloudComputing  •  Hard  •  Soft  •  Сети  •  Безопасность  •  Наука  •  IoT