Модель виджета служит для хранения отображаемых данных. В большинстве случаев для этих целей может использоваться обычный словарь вида:
В сложных GUI этой простой структуры становится недостаточно и приходится решать следующие задачи:
- Где и как хранить логику изменения модели?
- Как получать данные модели от сервера?
- Как проверять валидность модели при ее инициализации и изменении?
Объект модели
Представление модели в виде словаря достаточно простое и, часто, достаточное решение. В случае необходимости, логику для изменения данных в этом словаре можно вынести в методы самого виджета или сторонние сервисы:
В этом примере виджет OrderWidget
включает метод addOrderRow
, который был вынесен из модели и служит для измененя ее состояния. Модель же представляется здесь простым словарем model
и не содержит логики.
Плюсами данного решения являются:
- Простота реализации
Минусами:
- Запутанность логики, вызванная вынесением некоторых методов, относящихся к модели в виджет
- Ориентация на процедурную парадигму программирования, лишающую разработчика выгод объектной-ориентации
Альтернативным решением является представление всех сущностей модели в виде отдельных классов:
Здесь логика изменения состояния модели является частью самой модели и вызывается непосредственно.
Плюсами данного решения являются:
- Очевидность структуры модели
- Объектная-ориентация, позволяющая, в том числе, использовать наследование моделей для их расширения и вынесения общих семантик
Минусами:
- Сложность реализации, вызванная необходимостью дублировать модель бизнес-логики сервера на уровне представления
Для конкретной задачи необходимо выбирать ту реализацию, которая более приемлема и требует наименьших усилий. Так, для простого виджета вполне может подойти использование словаря в качестве модели, но сложный GUI лучше реализовывать с использованием классов модели.
Не бойтесь смешивать оба решения в одном проекте, вполне допустимо использовать словарь для некоторых простых виджетов и при этом классы моделей в остальных случаях. В случае усложнения виджета, использующего словарь вы легко замените решение, просто представив словарь в виде объекта и вынесев в него методы взаимодействия.
Получение модели
AJAX
В Web-разработке модель виджета должна быть получена от сервера. Сделать это можно используя AJAX запрос к соответствующему методу API, а полученные данные преобразовать в модель. В этом решении необходимо ответить на два вопроса:
- Кто должен отвечать за выполнение AJAX запроса?
- Кто должен отвечать за преобразование полученных от сервера данных в модель?
Первый вопрос решается двумя альтернативными подходами:
- Сама модель отвечает за запрос данных с сервера. В таком случае модель должна быть реализована в виде класса с дополнительной логикой, так как простого словаря будет не достаточно. Некоторым такое решение может не понравится, так как оно требует переноса логики, не относящийся к модели в классы этой модели.
- Сторонние сервисы отвечают за запрос данных с сервера. В таком случае модель освобождается от лишней для нее логики, но это усложняет структуру виджета и добавляет новые зависимости.
Каждое решение имеет свои сильные и слабые стороны, но их лучше не комбинировать, а выбрать одну альтернативу, так как использование обоих решений в одном проекте только усложнит его структуру.
Второй вопрос (кто должен отвечать за преобразование полученных от сервера данных в модель) может быть решен множеством способов, но мы рассмотрим только два из них:
- Модель расширяется методом, способным восстанавливать ее из “сырых” данных. Это довольно простое решение, но требующее некоторого усложнения структуры класса модели.
- Используется сторонний сервис для восстановления модели.
Hydration
Использование AJAX запросов для получения данных модели представления требует не только реализации API, но и часто сводит реализацию к Web-приложению. Другими словами, частью логики, отвечающая за отображение данных пользователю, полностью переносится в слой представления, а сервер лишается функций шаблонизации (это так же называется WebApp или одностраничным сайтом).
Если вы не готовы к таким изменениям, используйте метод hydration
для восстановления данных модели прямо из HTML разметки. Делается это очень просто:
В данном случае метод hydrate
вызывает виджетом только при указанном элементе HTML, из которого и должны быть восстановлены данные модели, а так же при отсутствии самой модели в конструкторе виджета. Метод hydrate
пытается восстановить модель виджета из созданной ранее сервером HTML страницы.
Это решение не требует использования AJAX запросов, но может использоваться вместе с ним. Не пугайтесь, если вы увидите виджет, который умеет как запрашивать данные от сервера, так и восстанавливать их прямо из страницы.
Основным минусом данного решения является необходимость использования двух шаблонизаторов, как на стороне сервера, так и на стороне клиента. При этом если серверная логика реализуется не на том же языке программирования, что и клиентская, это приведет к дублированию шаблонов.
Верификация модели
После получения модели виджетом и при каждом изменении ее состояния необходимо проверить, не нарушены ли правила верификации. К примеру, для модели Order
не допустимо оставлять свойство client
незаполненным. Чтобы выполнить верификацию модели я предлагаю единственное, на мой взгляд, верное решение - реализовывать методы верификации прямо в модели и вызывать их при необходимости. Учтите, что методов верификации может быть больше одного, это актуально, если модель представления имеет множество состояний (о верификации объектов мы еще подробно поговорим в другой статье).
Метод isValid
должен вызываться разработчиком самостоятельно в те моменты, когда валидность модели представления наиболее критична. К примеру, этот метод можно вызвать перед передачей модели серверу для сохранения, чтобы убедиться, что она находится в пригодном для сохранения виде (конечно, требуется дополнительная верификация на сервере, но данное решение позволит отсеять часть невалидных запросов и предупредить пользователя об ошибках):