Содержание

Интерфейсы. Прочь от MVC

Большинство сложных программных систем создаются с использованием паттерна MVC.

Многие программисты, приходя на javascript с других языков, по инерции используют этот подход.

Однако, при программировании javascript-интерфейса он зачастую бесполезен, приводит к тормозам, переусложнению приложений…

В javascript-интерфейсах, в отличие от Java/C++ и других — обычно не нужен паттерн MVC.

Применение паттерна MVC заключается в разделении собственно данных, их отображения и обработки действий пользователя по трем компонентам.

Модель (Model)
Собственно данные, методы для работы с данными, изменения и обновления данных.
Представление/Вид (View)
Отображение данных, оформление и другие аспекты презентации модели
Контроллер (Controller)
Реагирует на действия пользователя, интерпретирует данные, введенные пользователем, и информирует модель и производит необходимые манипуляции с моделью и видом.

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

Главный тезис статьи можно сформулировать так:

Controller пусть остается отдельно, а Model от View отделять не надо. Особенности Javascript/DOM/CSS позволяют успешно реализовывать аспекты Model средствами View.

Дальнейшая часть статьи — обоснование с примерами, почему именно так, а не иначе, и почему устоявшаяся практика MVC для javascript-интерфейсов работает плохо.

Никто не говорит о том, что MVC вообще — это плохо. Наоборот, MVC — это хорошо. Но вся штука в том, что при программировании для Web есть как минимум 3 важных особенности.

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

Будем исходить из предположения, что разрабатываем сложный интерфейс.
В самом деле, если интерфейс заведомо простой (и таким останется) — то лишние паттерны тем более не нужны.

Javascript/DOM в браузере — не самая быстрая платформа, а приложения фактически являются real-time, т.е интерфейс должен реагировать и отображаться по возможности мгновенно, плавно, и не сильно жрать память.

Межкомпонентные коммуникации Model-View добавляют тормозов. Это повод их убрать.

Далее, и модель и вид в javascript, как правило, оперируют данными в одинаковом формате.

То есть, значение в форме input.value — не рисованный объект типа GraphicsTTFString, как это может быть в обычном десктоп-програмировании, не кодированная строка пикселей, а обычный текст.

Поэтому отделение Model от View приводит к излишнему дублированию данных.

Что такое View в javascript-интерфейсах?

Это в первую очередь DOM и CSS. Модель DOM заранее включает в себя следующее:

При этом основные аспекты оформления задаются вообще отдельно от DOM, при помощи CSS.

Вы видите, DOM — это совсем не тот «классический» View, который обычно имеется в виду. Он гораздо мощнее.

Так зачем нам поддерживать иерархию, средства выборки и контейнеры для свойств в специальных javascript-объектах Модели, если с этим замечательно справляется DOM/View ?

Минусы, как и плюсы, связаны с производительностью.

При работе исключительно с javascript, работа идет в едином пространстве интерпретатора javascript. Это куда быстрее, чем обращаться к DOM-объектам, который в Microsoft относятся к COM, в Firefox — к XPCOM, в общем — живут отдельно от javascript-движка.

Эта проблема раньше была очень актуальна для Internet Explorer.

На момент написания статьи она фактически решена как библиотечными средствами (clobbering, учет и зачистка назначаемых DOM-элементам свойств), так и патчами.

В частности, как в IE7, так и в IE6 с обновлениями середины 2007 связка DOM-javascript почти не течет.

При разработке приложений надо смотреть, насколько тесно изменение ее модели (данных) завязано на изменение представления (DOM).

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

Однако обычно обновление данных тесно завязано с обновлением их вида, и это еще один довод к тому, чтобы их не разделять.

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

Современные js-фреймворки (YUI, dojo, jQuery) ликвидируют бОльшую часть утечек памяти.

Полностью впихивать Model во View, конечно, не обязательно. Да оно обычно и не нужно.

Можно выделить три устоявшихся практики.

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

Например, во вложенном меню это будет единый объект Menu, который умеет show/hide любые подменю. При этом подменю как таковое не является javascript-объектом.

Аналогично, в javascript-дереве это может быть единый объект Tree, который манипулирует узлами, а сами узлы — просто элементы DOM и хранят данные непосредственно в DOM.

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

Например, рассмотрим контекстное меню для javascript-дерева, которое вызывается правым кликом мыши на элементе.

Вместо пачки меню — для каждого элемента дерева своё, создается единый объект ContextMenu.

При клике на узел:

  1. ContextMenu инициализуется нужным узлом
  2. В зависимости от узла и прав на этот узел включает-выключает пункты подменю
  3. Показывается на нужном месте экрана

Приспособление ContextMenu

к конкретному элементу выполняется очень просто. В данном случае — не нужно создавать DOM-структуру меню, она и так есть. Не надо и создавать новый объект со своими методами — достаточно тех что есть.

Наконец, иногда целесообразно частично отделить некоторые аспекты Model от View.

Обычно при этом выводится в модель то, что во View хранить нельзя или неудобно, так чтобы не возникало дублирование.

В этой статье содержатся те мысли и подходы, которые отличают профессионального JS-программиста от обычного десктоп-кодера, подсевшего на javascript.

Их применение ведет к уменьшению и упрощению кода. Успехов.

javascript — Подход MVC для JavaScript

Я ищу подходящую структуру для организации моего кода с поддержкой Javascript и jQuery в соответствии с микроархитектурой MVCS.

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

На самом деле я ищу что-нибудь элегантное, например порт jQuery- PureMVC (который, насколько мне известно, не существует) или Robotlegs (для тех, кто знаком с этой структурой AS3).

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

Есть рекомендации?

2

webwise 16 Фев 2011 в 18:47

2 ответа

Лучший ответ

Попробуйте backbone.js

Backbone предоставляет структуру для приложений, насыщенных JavaScript, предоставляя моделям привязку значения ключа и настраиваемые события, коллекции с богатым API перечислимых функций, представления с декларативной обработкой событий и соединяет все это с существующим приложением через интерфейс RESTful JSON.

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

1

Raynos 16 Фев 2011 в 16:28

JavaScript-приложение, или зачем нам Razor в ASP.NET MVC?

Не думал, что напишу это, но JavaScript победил. Мы перестали использовать Razor для создания веб-приложений. Вместо этого реализуем front-end в отдельном проекте на JavaScript-фреймворках. От ASP.NET остался только WebAPI и «движок», на котором мы пишем бизнес-логику и API для пользовательского интерфейса.

Вселенная JavaScript и CSS

Последнее время мы наблюдаем взрывное развитие веб-технологий. Появились полноценные IDE для работы с HTML/CSS/JavaScript, проекты типа Grunt и сотни JavaScript-фреймворков. Инфраструктура для создания front-end’а стала взрослой.

Давайте посмотрим на статистику Github. Я нашел два источника статистики по языкам программирования, в обоих JavaScript стоит на первом месте.

В статье Language Trends on GitHub посчитали с помощью Linguist, что JavaScript на первом месте на GitHub по популярности, среди языков программирования:

GitHut показывает аналогичную ситуацию:

Теперь я понимаю откуда каждую неделю появляются новые JavaScript-фреймворки. Могу себе представить трудозатраты сообщества JavaScript-программистов, которые поставили JavaScript на первое место на github.

Миф о кроссфункциональности

Мы отказываемся верить во всемогущих full-stack web-разработчиков. Full-stack означает, что программист разбирается и в .NET, и в JavaScript/CSS.

Что значит разбираться в этих двух мирах? Это значит знать тонкости работы с браузерами, знать и практиковаться с новыми JavaScript-фреймворками, и одновременно с этим знать о новых фишках в C#, изменениях в платформе .NET, следить за новыми версиями ASP.NET MVC и новым базами данных. Такого всезнающего full-stack web-разработчика я последний раз видел… никогда. Охватить и стать экспертом в этих двух областях не под силу смертному. Я не говорю о людях с железным стержнем и безграничным запасом свободного времени, речь об обычных людях типа меня.

Если вы спросите меня, знаю ли я JavaScript и CSS? Я отвечу, что знаю. Но знаю ли я эти технологии достаточно, чтобы создать качественное решение на front-end? Нет, моих знаний недостаточно, я знаю эти технологии поверхностно по сравнению, например, с front-end разработчиками нашей компании.

Я пришел к выводу, что сложный проект не создать силами full-stack разработчиков . Если речь о сложном UI и сложном back-end, то специализация необходима. Доверять full-stack разработчикам проекты сложнее, чем натягивание дизайна на CMS, настройки интерфейса в SharePoint или кастомизации Bootstrap — губительно для проекта.

История из соседней компании. Lead .NET разработчик усмотрел проблемы на front-end. Он решил, что у UI-проекта неправильная архитектура и технический долг, поэтому он пошел наводить там порядок. В итоге стало еще хуже, чем было, потому что JavaScript-приложение он создавать не умел.

Я думаю похожая ситуация могла бы произойти, если бы JavaScript-разработчик полез в C#. Разница в том, что .NET разработчики считают, что смогут корректно поправить JavaScript/CSS, а front-end разработчики знают, что им в C# лучше не залезать и они не лезут.

Схема взаимодействия

На старте работы мы делаем два проекта. Первый проект традиционный — ASP.NET Web API приложение в Visual Studio, второй проект в Webstorm. Оба проекта лежат в одном репозитории, хотя это не обязательно.

Front-end разработчики согласуют с back-end разработчиками API, через которое происходит взаимодействие двух приложений.

Процесс работы

Мы создаем проектные команды, поэтому разработчики, QA и другие члены команды входят в состав единой команды проекта. В том числе front-end и back-end разработчики входят в эту команду. Единая команда работает с Impact Mapping, Customer Journey Mapping, User Story Mapping, которые появляются во время процесса создания ПО:

Видно, что с точки зрения процесса создания ПО, мы никак не разделяем front-end и back-end части. Это осознанный шаг, который помогает делать поставку бизнес-ценности.

Плюсы и минусы

В разделении front-end и back-end на два проекта я нахожу и плюсы и минусы:

  • Плюсы
    1. Front-end и back-end проекты слабо связаны. Становится возможно развиваться эти проекты параллельно или отдельно друг от друга.
    2. У вас случалось, что кроме веб-интерфейса, вас просят создать API к Android-приложению? У нас заказчики просили об этом и не раз. Если вы изначально создаете API, документируете API, то подключение новых клиентов к нему не составляет труда.
    3. Выкладка  front-end и back-end частей теперь может происходить независимо. Вам не придется перезаливать монолитное ASP.NET MVC приложение из-за изменений в JavaScript/CSS или разметки.
    4. Чем сложнее проект, тем сложнее управлять монолитным ASP.NET MVC приложением. Если разнести единое приложение на два проекта, как показано в статье, то развивать два небольших проекта проще.
    5. В монолитном ASP. NET MVC приложение цена ошибки это весь проект. В раздельных проектах цена ошибки это части системы.
  • Минусы
    1. Нужны сильные front-end разработчики, которые могут и не понадобится, если full-stack разработчики создают back и front.
    2. Следствие из предыдущего пункта — нужно больше людей в проект.
    3. Инфраструктура сложнее, усложняется процесс сборки релиза.
    4. Дополнительно время тратиться на согласование API между двумя проектами.
    5. Изменения в бизнес-логике часто затрагивают оба проекта.

Выбор подхода

Мы выбираем ASP.NET MVC приложение и рендер HTML через Razor, если используем CMS или пишем небольшой проект без сложной бизнес-логики. Например, так сделан сайт компании ByndyuSoft. Мы выбираем front-end в виде JavaScript-приложения во всех остальных случаях.

Оригинал статьи на Хабре http://habrahabr.ru/post/275333

Ссылки:

  1. Backend For Frontend (BFF) Pattern

Архитектура Model-View-Controller (MVC) для приложений Node

MVC является аббревиатурой от Model-View-Controller.
Это шаблон проектирования для программных проектов. Он в основном используется разработчиками Node, а также пользователями C #, Ruby, PHP Framework.
В паттерне MVC приложение и его разработка разделены на три взаимосвязанные части. Преимущество этого состоит в том, что он помогает сфокусироваться на определенной части имени приложения, способах представления и получения информации от пользователя. Это помогает обеспечить эффективное повторное использование кода и параллельную разработку приложения. Даже если структура проекта может выглядеть немного иначе, чем идеальная структура MVC, основной поток программы внутри и снаружи приложения остается неизменным.

В этом посте поток программ между этими компонентами приложения будет показан при создании демонстрационного приложения.

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

объяснение

Модель : Модель представляет структуру данных, формат и ограничения, с которыми они хранятся. Он поддерживает данные приложения. По сути, это часть базы данных приложения.

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

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

  • Модель является частью данных.
  • Вид является частью интерфейса пользователя.
  • Контроллер является обработчиком запроса-ответа.

Архитектура MVC

Теперь давайте начнем с приложения .
Здесь npm init используется для генерации файла package.json и app.js.

NPM-INIT

Как следует из названия, есть три папки, называемые моделями, представлениями, контроллерами, которые помогут в реализации архитектуры mvc.
npm используется для установки основных пакетов npm для начала работы.

NPM-пакет-установки-чик

Структура проекта выглядит следующим образом.

MVC-проект-структура Snip

Объяснение структуры проекта

  • Как видите, есть папка маршрутов , которая будет служить в качестве контроллеров .
  • Тогда есть папка моделей , в которой у нас есть пользовательская модель .
  • Папка views , в которой есть наши представления с расширением . handlebars . Обратите внимание, что руль — это шаблонизатор, который означает, что он способен генерировать страницы, заполняя создаваемые нами шаблоны.

Теперь давайте перейдем к демонстрации того, как шаблон MVC реализуется для процесса входа в систему и регистрации в качестве пользователя в этой демонстрационной версии LoginApp.

  1. Напишите узел app.js, чтобы запустить приложение. Приложение запустится, если все правильно, иначе попытайтесь отладить приложение, используя stackoverflow и тому подобное.
  2. Откройте приложение в вашем браузере. Если вы подписали и используете мое репозиторий github, перейдите к localhost: 3000 в своем браузере, и вы увидите, что приложение работает. Когда вы откроете приложение в своем браузере, ваш файл app.js скажет себе что-то вроде: «О ! Браузер запросил localhost: 3000 / , поэтому давайте посмотрим на файл, который будет обслуживаться, если будет достигнут этот маршрут. Это выглядит для этого кода:

    Приложение использует маршрут appjs

    ,

    Он сообщает приложению, которое использует переменную route, если запрашивается ‘/’ . Затем он ищет переменную маршрутов. Он находит его в файле app.js здесь:

    Маршруты требует

    ,

    Теперь он ищет в файле gfgIndex.js в папке маршрутов нашего приложения узла, чтобы найти код, который будет выполняться при достижении маршрута ‘/’.
    Находит следующий код.

    Файл маршрутов GfgIndexjs

    Этот код в основном говорит, что визуализирует index.hanblebars, если пользователь вошел в систему. Чтобы проверить, вошел ли пользователь в систему, он запускает функцию sureAuthenticated .
    Эта функция в основном говорит, что если пользователь вошел в систему, отобразите файл index.handlebars, иначе перенаправьте пользователя на маршрут / users / login .

    GfgUsersjs логин маршрут снип

    Этот код сообщает приложению, что нужно обработать файл index. handlebars при вызове GET ‘/’. Итак, теперь он переходит в папку views и ищет index.handlebars и отображает его для пользователя.
    Вот как часть архитектуры views-controller работает в приложении. Я считаю, что приведенный выше поток программ понятен читателю.

  3. Теперь давайте перейдем к процессу регистрации тестового пользователя, чтобы увидеть, как работает модель.

  4. Перейдите по адресу http: // localhost: 3000 / users / register . Итак, приложение разбивает маршрут на две части: / users и / register и запрашивает у себя что-то вроде «О, хорошо! Пользователи хотят видеть / users route и затем / зарегистрироваться . Приложение ищет файл «/ users» в своем файле app.js и находит его здесь.

    Приложение использует маршрут appjs

    ,

    Затем он ищет переменную ‘users’ для использования при попадании в путь / users, которую можно найти в файле app.js:

    Маршруты требует

    ,

    Итак, он идет в файл gfgUsers. js в папке маршрутов и ищет маршрут / регистр. Обратите внимание, что / users / register находится в файле gfgUsers.js как / register . Он просит браузер отобразить файл ‘register.handlebars’ . Это арка вида-контроллера. реализация продолжается.
    Вторая часть регистрации Теперь давайте зарегистрируем нового пользователя.

    Зарегистрируйте нового пользователя Snap. Изображение: https: //media.geeksforgeeks.org/wp-content/uploads/register-a-new-user-snap.png

    После нажатия на кнопку «Отправить» данные принимаются, отправляются в POST по маршруту «/ register» для обработки. Этот контроллер проверяет входящие данные на наличие ошибок, а затем создает новую переменную с именем NEWUSER с пользователем моделируется по образцу со всеми данными и вызовы Save () на нем на самом деле сохранения данных для пользователя.

    Новая пользовательская консоль вошла в терминал

    После того, как пользователь создан, контроллер «/ register» просит браузер перенаправить пользователя на страницу «/ login» . Это реализация архитектуры модель-представление-контроллер.

Вы можете найти весь код, используемый в этой статье здесь . Вилка, клон и беги.

Рекомендуемые посты:

Архитектура Model-View-Controller (MVC) для приложений Node

0.00 (0%) 0 votes

Создание простого приложения MVC с нуля на JavaScript

Я хотел написать простое приложение на простом JavaScript, используя архитектурный шаблон модель-представление-контроллер. Я так и сделал, и вот оно. Надеюсь, это поможет вам понять MVC, поскольку это сложная концепция, которую сложно осмыслить, когда вы только начинаете.

Я сделал это приложение для задач, которое представляет собой простое небольшое приложение для браузера, которое позволяет выполнять CRUD (создавать, читать, обновлять и удалять) задачи. Он просто состоит из индекса .html , style.css и script.js , такие приятные и простые и не требующие зависимостей / фреймворков для учебных целей.

Предварительные требования
Голы

Создайте приложение todo в браузере с помощью простого JavaScript и познакомьтесь с концепциями MVC (и ООП — объектно-ориентированного программирования).

Примечание: Поскольку это приложение использует новейшие функции JavaScript (ES2017), оно не будет работать как есть в некоторых браузерах, таких как Safari, без использования Babel для компиляции с обратно совместимым синтаксисом JavaScript.

Что такое контроллер представления модели?

MVC — это один из возможных шаблонов для организации вашего кода. Это популярный.

  • Модель — управляет данными приложения
  • Вид — Визуальное представление модели
  • Контроллер — связывает пользователя и систему

Модель — это данные. В этом приложении задач это будут фактические задачи и методы, которые будут добавлять, редактировать или удалять их.

Представление — это способ отображения данных. В этом приложении todo это будет обработанный HTML в DOM и CSS.

Контроллер соединяет модель и вид. Он принимает пользовательский ввод, такой как щелчок или ввод, и обрабатывает обратные вызовы для взаимодействия с пользователем.

Модель никогда не трогает вид. Вид никогда не касается модели. Контроллер их соединяет.

Я хотел бы упомянуть, что создание MVC для простого приложения todo на самом деле представляет собой тонну шаблонов.Было бы действительно сложно, если бы это было то приложение, которое вы хотели создать, и вы создали всю эту систему. Дело в том, чтобы попытаться понять это на небольшом уровне, чтобы вы могли понять, почему масштабируемая система может его использовать.

Начальная настройка

Это будет приложение полностью на JavaScript, что означает, что все будет обрабатываться через JavaScript, а HTML будет состоять только из одного корневого элемента в теле.

index.html

  

  
    
    
    

     Приложение Todo 

    
  

  
    

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

Хорошо, теперь, когда у нас есть HTML и CSS, пора фактически начать писать приложение.

Начало работы

Мы собираемся сделать это действительно красивым и простым, чтобы понять, какой класс относится к какой части MVC. Я создам класс Model , View class и Controller class, которые принимают модель и вид. Приложение будет экземпляром контроллера.

Если вы не знакомы с принципами работы классов, прочтите «Понимание классов в JavaScript».

  модель класса {
  конструктор () {}
}

class View {
  конструктор () {}
}

class Controller {
  конструктор (модель, представление) {
    this.model = модель
    this.view = просмотр
  }
}

const app = новый контроллер (новая модель (), новый вид ())  

Очень красиво и абстрактно.

Модель

Давайте сначала сосредоточимся на модели, так как это самая простая из трех частей. Это не связано с какими-либо событиями или манипуляциями с DOM. Это просто хранение и изменение данных.

Модель

  модель класса {
  constructor () {
    
    это.todos = [
      {id: 1, текст: "Беги марафон", завершено: false},
      {id: 2, текст: "Посадить сад", завершено: false},
    ]
  }

  addTodo (todoText) {
    const todo = {
      id: this.todos.length> 0? this. todos [this.todos.length - 1] .id + 1: 1,
      текст: todoText,
      завершено: false,
    }

    this.todos.push (задача)
  }

  
  editTodo (id, updatedText) {
    this.todos = this.todos.map ((todo) =>
      todo.id === id? {id: todo.id, text: updatedText, complete: todo.complete}: todo,
    )
  }

  
  deleteTodo (id) {
    это.todos = this.todos.filter ((todo) => todo.id! == id)
  }

  
  toggleTodo (id) {
    this.todos = this.todos.map ((todo) =>
      todo.id === id? {id: todo.id, text: todo.text, complete:! todo.complete}: todo,
    )
  }
}  

У нас есть addTodo , editTodo , deleteTodo и toggleTodo . Все это должно быть самоочевидным — add добавляет новую задачу к массиву, edit находит идентификатор задачи для редактирования и заменяет ее, удаляет фильтрует задачу из массива и переключает переключатели логического свойства complete .

Поскольку мы делаем все это в браузере, а приложение доступно из окна (глобального), вы можете легко проверить это, набрав что-то вроде:

  app. model.addTodo ('Вздремнуть')  

добавит задачу в список, и вы можете записать содержимое app.model.todos .

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

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

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

Посмотреть

Мы собираемся создать представление, манипулируя DOM — объектной моделью документа.Поскольку мы делаем это на простом JavaScript без помощи React JSX или языка шаблонов, это будет довольно многословно и некрасиво, но такова природа прямого управления DOM.

Ни контроллер, ни модель не должны знать ничего о DOM, элементах HTML, CSS или обо всем этом. Все, что связано с этим, должно быть в поле зрения.

Если вы не знакомы с DOM или чем DOM отличается от исходного кода HTML, прочтите Введение в DOM.

Первое, что я сделаю, это просто создам вспомогательные методы для извлечения элемента и создания элемента.

Посмотреть

  class View {
  конструктор () {}

  
  createElement (tag, className) {
    const element = document.createElement (тег)
    если (имя класса) element.classList.add (имя класса)

    возвратный элемент
  }

  
  getElement (selector) {
    const element = document.querySelector (селектор)

    возвратный элемент
  }
}  

Пока все хорошо. Теперь в конструкторе я собираюсь настроить все, что мне нужно для моего представления.Это будет:

  • Корневой элемент приложения — #root
  • Заголовок — h2
  • Форма, кнопка ввода и отправки для добавления задачи — форма , ввод , кнопка
  • Список дел — ul

Я сделаю их все переменными в конструкторе, чтобы мы могли легко ссылаться на них.

Посмотреть

  class View {
  constructor () {
    
    this.app = это.getElement ('# корень')

    
    this.title = this.createElement ('h2')
    this.title.textContent = 'Todos'

    
    this.form = this.createElement ('форма')

    this.input = this.createElement ('ввод')
    this.input.type = 'текст'
    this.input.placeholder = 'Добавить задачу'
    this.input.name = 'todo'

    this.submitButton = this.createElement ('кнопка')
    this.submitButton.textContent = 'Отправить'

    
    this.todoList = this.createElement ('ul', 'список задач')

    
    this.form.append (this.input, this.submitButton)

    
    this.app.append (this.title, this.form, this.todoList)
  }
  
}  

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

Еще две мелочи — геттер и сброс входного (нового todo) значения.

Я использую символы подчеркивания в именах методов, чтобы указать, что это частные (локальные) методы, которые не будут использоваться вне класса.

Посмотреть

  get _todoText () {
  верни это.input.value
}

_resetInput () {
  this.input.value = ''
}  

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

Посмотреть

Метод displayTodos создаст ul и li s, из которых состоит список задач, и отобразит их. Каждый раз, когда задача изменяется, добавляется или удаляется, метод displayTodos будет вызываться снова с todos из модели, сбрасывая список и повторно отображая их.Это позволит синхронизировать вид с состоянием модели.

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

Посмотреть

 
while (this.todoList. firstChild) {
  this.todoList.removeChild (this.todoList.firstChild)
}


if (todos.length === 0) {
  const p = this.createElement ('p')
  p.textContent = 'Нечего делать! Добавить задачу? '
  this.todoList.append (p)
} еще {
  
}  

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

Посмотреть

  else {
  
  todos.forEach (todo => {
    const li = this.createElement ('ли')
    li.id = todo.id

    
    const checkbox = this.createElement ('ввод')
    checkbox.type = 'флажок'
    checkbox.checked = todo.complete

    
    const span = this.createElement ('диапазон')
    span.contentEditable = true
    span.classList.add ('редактируемый')

    
    if (todo.complete) {
      const strike = this.createElement ('s')
      strike.textContent = todo.text
      охватывать.добавить (удар)
    } еще {
      
      span.textContent = todo.text
    }

    
    const deleteButton = this.createElement ('кнопка', 'удалить')
    deleteButton. textContent = 'Удалить'
    li.append (флажок, диапазон, deleteButton)

    
    this.todoList.append (ли)
  })
}  

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

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

Контроллер

Наконец, контроллер является связующим звеном между моделью (данными) и представлением (тем, что видит пользователь). Вот что у нас есть в контроллере.

Контроллер

Контроллер класса
  {
  конструктор (модель, представление) {
    this.model = модель
    this.view = просмотр
  }
}  

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

Контроллер

Контроллер класса
  {
  конструктор (модель, представление) {
    this.model = модель
    this.view = просмотр

    
    this.onTodoListChanged (this.model.todos)
  }

  onTodoListChanged = (todos) => {
    this.view.displayTodos (задачи)
  }
}  

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

Создадим обработчики событий в контроллере.

Контроллер

  handleAddTodo = (todoText) => {
  this.model.addTodo (todoText)
}

handleEditTodo = (id, todoText) => {
  this.model.editTodo (идентификатор, todoText)
}

handleDeleteTodo = (id) => {
  this.model.deleteTodo (идентификатор)
}

handleToggleTodo = (id) => {
  это. model.toggleTodo (id)
}  

Настройка прослушивателей событий

Теперь у нас есть эти обработчики, но контроллер все еще не знает, когда их вызывать. Мы должны поместить слушателей событий в элементы DOM в представлении. Мы ответим на событие submit в форме, а щелкнем и изменим событий в списке задач. (Я пока пропускаю «Редактировать», так как это немного сложнее.)

Посмотреть

  bindAddTodo (обработчик) {
  это.form.addEventListener ('submit', event => {
    event.preventDefault ()

    if (this._todoText) {
      обработчик (this._todoText)
      this._resetInput ()
    }
  })
}

bindDeleteTodo (обработчик) {
  this.todoList.addEventListener ('щелчок', событие => {
    if (event.target.className === 'delete') {
      const id = parseInt (event.target.parentElement.id)

      обработчик (идентификатор)
    }
  })
}

bindToggleTodo (handler) {
  this.todoList.addEventListener ('изменение', событие => {
    if (event. target.type === 'checkbox') {
      const id = parseInt (event.target.parentElement.id)

      обработчик (идентификатор)
    }
  })
}  

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

Мы использовали стрелочные функции для всех событий дескриптора. Это позволяет нам вызывать их из представления с использованием контекста и контроллера. Если бы мы не использовали стрелочные функции, нам пришлось бы связывать их вручную, например this.view.bindAddTodo (this.handleAddTodo.bind (this)) .Ой.

Контроллер

  this.view.bindAddTodo (this.handleAddTodo)
this.view.bindDeleteTodo (this.handleDeleteTodo)
this.view.bindToggleTodo (this.handleToggleTodo)
  

Теперь, когда submit , click or change event происходит на указанных элементах, будут вызваны соответствующие обработчики.

Ответить на обратные вызовы в модели

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

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

Мы уже сделали метод onTodoListChanged на контроллере, чтобы справиться с этим, нам просто нужно сделать так, чтобы модель знала об этом.Мы привяжем его к модели так же, как и с обработчиками в представлении.

В модели добавьте bindTodoListChanged для onTodoListChanged .

Модель

  bindTodoListChanged (обратный вызов) {
  this. onTodoListChanged = обратный вызов
}  

И вы привяжете это в контроллере, как и в случае с представлением.

Контроллер

  this.model.bindTodoListChanged (this.onTodoListChanged)  

Теперь после каждого метода в модели вы вызовете обратный вызов onTodoListChanged .

Модель

  deleteTodo (id) {
  this.todos = this.todos.filter (todo => todo.id! == id)

  this.onTodoListChanged (this.todos)
}  

Добавить локальное хранилище

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

Если вы не знаете, как работает локальное хранилище, прочтите Как использовать локальное хранилище с JavaScript.

Теперь мы можем установить начальное значение задачи, которое находится в локальном хранилище или в пустом массиве.

Модель

  модель класса {
  constructor () {
    this.todos = JSON.parse (localStorage.getItem ('todos')) || []
  }
}  

Мы сделаем частный метод commit , чтобы обновить значение localStorage , а также состояние модели.

Модель

  _commit (todos) {
  this.onTodoListChanged (задачи)
  localStorage.setItem ('задачи', JSON.stringify (задачи))
}  

После каждого изменения в this.todos мы можем вызывать его.

Модель

  deleteTodo (id) {
  this.todos = this.todos.filter (todo => todo.id! == id)

  this._commit (this.todos)
}  

Добавить функцию редактирования в реальном времени

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

Я решил создать метод в представлении, который обновляет временную переменную состояния с новым значением редактирования, и другой метод, который вызывает метод handleEditTodo в контроллере, который обновляет модель. Событие input — это то, что запускается, когда вы вводите contenteditable элемент , а focusout срабатывает, когда вы оставляете contenteditable элемент .

Посмотреть

  constructor () {
  
  this._ ContemporaryTodoText
  this._initLocalListeners ()
}


_initLocalListeners () {
  this.todoList.addEventListener ('input', event => {
    if (event.target.className === 'editable') {
      this._ ContemporaryTodoText = event.target.innerText
    }
  })
}


bindEditTodo (handler) {
  this.todoList.addEventListener ('focusout', event => {
    if (this. _ ContemporaryTodoText) {
      const id = parseInt (event.target.parentElement.id)

      обработчик (id, this._ ContemporaryTodoText)
      this._ ContemporaryTodoText = ''
    }
  })
}  

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

Просто не забудьте привязать обработчик editTodo .

Контроллер

  this.view.bindEditTodo (this.handleEditTodo)  

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

Заключение

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

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

Почему я больше не использую MVC Framework

Узнайте, на какие технологии из области веб-разработки вам стоит обратить внимание в этом году. Станьте новатором в своей команде и узнайте больше о Vue.js, GraphQl и React. Прочитать отчет .

В наши дни худшая часть моей работы — это разработка API для интерфейсных разработчиков. Разговор неизбежно идет как:

Dev — Итак, на этом экране есть элементы данных x, y, z… не могли бы вы создать API с форматом ответа {x:, y :, z:}

мне — хорошо

Я даже не спорю.Проекты заканчиваются миллионом API-интерфейсов, привязанных к часто меняющимся экранам, которые по «дизайну» требуют изменений в API, и, прежде чем вы это узнаете, вы получите множество API-интерфейсов, а для каждого API — множество форм-факторов и вариантов платформы. Сэм Ньюман даже начал процесс институционализации этого подхода с помощью шаблона BFF, который предполагает, что можно разрабатывать определенные API-интерфейсы для каждого типа устройства, платформы и, конечно же, версий вашего приложения. Дэниел Джейкобсон объясняет, что Netflix был загнан в угол, чтобы использовать новый квалификатор для своих «API опыта»: эфемерный.Вздох…

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

За каждым используемым нами экраном стоит шаблон MVC –Model-View-Controller.MVC был изобретен, когда еще не было Интернета, и программные архитектуры были, в лучшем случае, толстыми клиентами, которые напрямую общались с единой базой данных в примитивных сетях. И все же, спустя десятилетия, MVC все еще не ослабевает для создания приложений OmniChannel.

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

Впервые я столкнулся с MVC в 1990 году после того, как NeXT выпустила Interface Builder (удивительно, что эта программа актуальна и сегодня).В то время Interface Builder и MVC казались серьезным шагом вперед. В конце 90-х шаблон MVC был адаптирован для работы через HTTP (помните Struts?), И сегодня MVC во всех смыслах и целях является краеугольным камнем любой архитектуры приложения.

Даже React.js пришлось использовать эвфемизм, когда они представили фреймворк, который на этот раз, казалось, значительно отклонился от догмы MVC: «React — это просто представление в MVC».

Когда я начал использовать React в прошлом году, я почувствовал, что в этом есть что-то совсем другое: вы где-то меняете часть данных, и в одно мгновение, без явного взаимодействия между представлением и моделью, изменяется весь пользовательский интерфейс ( не только значения в полях и таблицах).При этом я был так же быстро разочарован моделью программирования React, и, видимо, я был не один. Я разделяю мнение Андре Медейроса:

React разочаровал меня во многих отношениях, в основном из-за плохо спроектированного API, который побуждает программиста […] смешивать несколько задач в одном компоненте.

Как разработчик серверных API-интерфейсов, я пришел к выводу, что не существует особо хорошего способа вплетения вызовов API в интерфейс React именно потому, что React фокусируется только на представлении и вообще не имеет контроллера в своей модели программирования.

Facebook до сих пор сопротивлялся устранению этого пробела на уровне фреймворка. Команда React впервые представила паттерн Flux, который не менее разочаровал, и в наши дни Дэн Абрамов продвигает другой паттерн, Redux, который идет в некотором роде в правильном направлении, но не предлагает надлежащего факторинга для подключения API к интерфейсу, как я буду показать ниже.

Вы могли подумать, что между GWT, Android SDK и Angular инженеры Google будут иметь четкое представление (каламбур) относительно того, что может быть лучшей интерфейсной архитектурой, но когда вы читаете некоторые соображения по дизайну Angular2, вы не понимаете: не обязательно испытывать такое теплое чувство, что даже в Google люди знают, что делают:

Angular 1 не строился вокруг концепции компонентов.Вместо этого мы прикрепили контроллеры к различным [элементам] страницы с помощью нашей собственной логики. Области видимости будут присоединяться или передаваться, в зависимости от того, как наши настраиваемые директивы инкапсулируются (изолировать область действия, кто-нибудь?).

Компонентный Angular2 выглядит намного проще? Не совсем. Один только базовый пакет Angular 2 имеет семантику 180, а весь фреймворк приближается к классной семантике 500, и это помимо HTML5 и CSS3. У кого есть время изучить и освоить такую ​​структуру для создания веб-приложения? Что происходит, когда появляется Angular3?

После использования React и просмотра того, что происходит в Angular2, я почувствовал себя подавленным: эти фреймворки систематически вынуждают меня использовать шаблон BFF «Screen Scraping», где каждый серверный API соответствует набору данных экрана, как внутри, так и снаружи.

Вот тогда-то и настал момент «к черту». Я просто создам веб-приложение без React, без Angular и вообще без инфраструктуры MVC, чтобы посмотреть, смогу ли я найти лучшую артикуляцию между View и базовыми API.

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

Если вы посмотрите достаточно долго, вы поймете, что единственная цель React — разложить представление на серию (чистых) функций и синтаксис JSX:

ничем не отличается от:

В = f (М)

Например, сайт Gliiph одного из проектов, над которым я сейчас работаю, построен с такой функцией:

(Щелкните изображение, чтобы увеличить его)

рис 1.Функция, отвечающая за создание HTML-кода компонента Slider

Эта функция питается от модели:

(Щелкните изображение, чтобы увеличить его)

рис 2. Режим за ползунками

Когда вы понимаете, что обычная старая функция JavaScript отлично справляется с этой задачей, ваш следующий вопрос: зачем вам вообще использовать React?

Виртуальный дом? Если вы чувствуете, что он вам нужен (а я не уверен, что многие люди), есть варианты, и я ожидаю, что будут разработаны другие.

GraphQL? Не совсем. Не дайте себя обмануть аргументом о том, что, если Facebook активно использует его, это должно быть полезно для вас. GraphQL — это не что иное, как декларативный способ создания модели представления. Принуждение к формированию модели в соответствии с видом — это проблема, а не решение. Как могла команда React (как в реактивном) подумать, что можно запрашивать данные с помощью «запросов, определяемых клиентом»:

GraphQL безоговорочно руководствуется требованиями представлений и интерфейсных инженеров, которые их пишут.[…] Запрос GraphQL, с другой стороны, возвращает именно то, что запрашивает клиент, и не более того.

Команда GraphQL, похоже, упустила то, что за синтаксисом JSX есть тонкое изменение, заключающееся в том, что функции изолируют модель от представления. В отличие от шаблонов или «запросов, написанных интерфейсными инженерами», функциям не требуется, чтобы модель соответствовала представлению.

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

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

Непосредственно встраивать эти вычисления в представление — не самая лучшая идея, но нетрудно также сделать модель представления чистой функцией, и, следовательно, нет особой веской причины использовать GraphQL, когда вам нужно явная модель представления:

V = f (vm (M))

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

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

Я не удивлюсь, например, если в ближайшие несколько месяцев люди начнут предоставлять темы HTML5 в виде компонентных функций JavaScript.В наши дни я делаю все свои проекты для веб-сайтов именно так: беру шаблон и сразу же оборачиваю его функциями JavaScript. Я больше не использую WordPress. Я могу извлечь максимум из HTML5 и CSS3 с примерно одинаковым уровнем усилий (или меньше).

Этот подход также требует нового типа отношений между дизайнерами и разработчиками. Кто угодно может написать эти функции JavaScript, особенно разработчики шаблонов. Нет никакого «связывающего» синтаксиса, который нужно изучить, нет JSX, нет шаблона Angular, просто старая обычная функция JavaScript.

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

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

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

Apple кое-что знает о MVC, поскольку они «украли» шаблон у Xerox PARC в начале 80-х и с тех пор неукоснительно внедряют его:

рис.3. Шаблон MVC

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

Тогда ключевым вопросом становится: как интегрировать действия в реактивный поток? Если вы хотите кое-что понять о действиях, вы можете взглянуть на TLA +.TLA означает «временную логику действий» — формализм, изобретенный доктором Лэмпортом, получившим за это премию Тьюринга. В TLA + действия — это чистые функции:

data ’= A (данные)

Мне очень нравится простая нотация TLA +, потому что она подчеркивает тот факт, что функции являются простыми преобразованиями в заданном наборе данных.

Имея это в виду, реактивный MVC, вероятно, будет выглядеть так:

V = f (M.present (A (данные)))

Это выражение предусматривает, что при запуске действия оно вычисляет набор данных из набора входных данных (например, пользовательских), которые представлены модели, которая затем решает, обновлять ли себя и как.После завершения обновления вид визуализируется из нового состояния модели. Реактивный контур замкнут. То, как модель сохраняется и извлекает свои данные, не имеет отношения к реактивному потоку и, конечно же, никогда, абсолютно никогда, не должно быть «написано интерфейсными инженерами». Без извинений.

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

Шаблон Reactive MVC интересен тем, что, за исключением модели (конечно), все остальное является чистой функцией.Честно говоря, Redux реализует этот конкретный шаблон, но с ненужной церемонией React и небольшой связкой между моделью и действиями в редукторе. Интерфейс между действиями и моделью — это чистая передача сообщений.

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

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

Это приложение имеет простой конечный автомат:

рис.4. Конечный автомат Ракетной установки

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

В MVC такая логика будет реализована в контроллере, возможно, запущена таймером в представлении.

Этот абзац очень важен, поэтому внимательно прочтите его. Мы видели, что в TLA + действия не имеют побочных эффектов, и результирующее состояние вычисляется после того, как модель обработала выходные данные действия и обновила себя. Это фундаментальный отход от традиционной семантики конечного автомата, в которой действие определяет результирующее состояние, т.е.е. результирующее состояние не зависит от модели. В TLA + действия, которые включены и, следовательно, доступны для запуска в представлении состояния (т. Е. В представлении), не связаны напрямую с действием, вызвавшим изменение состояния. Другими словами, конечные автоматы не должны указываться как кортежи, которые соединяют два состояния (S 1 , A, S 2 ), как это традиционно бывает, они скорее представляют собой кортежи вида (S k , A k1 , A k2 ,…), которые определяют все разрешенные действия, заданное состояние S k , при этом результирующее состояние вычисляется после того, как действие было применено к системе, и модель обработала обновления.

Семантика

TLA + обеспечивает превосходный способ концептуализации системы, когда вы вводите объект «состояние , », отдельно от действий и представления (который является просто представлением состояния ).

Модель в нашем примере выглядит следующим образом:

Модель

= {

счетчик:,

началось:,

прервано:,

запущен:}

Четыре (управляющих) состояния системы связаны со следующими значениями модели

готов = {счетчик: 10, начато: ложь, прервано: ложь, запущено: ложь}

подсчет = {счетчик: [0..10], начато: true, прервано: false, начато: false}

launch = {counter: 0, start: true, aborted: false, loaded: true}

aborted = {counter: [0..10], start: true, aborted: true, loaded: false}

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

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

(Щелкните изображение, чтобы увеличить его)

рис.5. Реализация ракетной установки

Обратите внимание, что в архитектуре клиент / сервер нам нужно будет использовать протокол, такой как WebSocket (или опрос, когда WebSocket недоступен), чтобы правильно отображать представление состояния после запуска автоматического действия,

Я написал очень тонкую библиотеку с открытым исходным кодом на Java и JavaScript, которая структурирует объект состояния с надлежащей семантикой TLA + и предоставил образцы, которые используют WebSocket, Polling и Queuing для реализации взаимодействий между браузером и сервером.Как вы можете видеть в примере с ракетной установкой, вы не должны чувствовать себя обязанным использовать эту библиотеку. Реализацию состояния относительно легко кодировать, если вы понимаете, как ее писать.

Я считаю, что теперь у нас есть все элементы для формального введения нового шаблона в качестве альтернативы MVC, шаблона SAM (State-Action-Model), реактивного, функционального шаблона, уходящего корнями в React.js и TLA +.

Шаблон SAM может быть представлен следующим выражением:

V = S (vm (M.присутствует (A (данные))), дремота (M))

, который предусматривает, что вид V системы может быть вычислен после применения действия A как чистая функция модели.

В SAM, A (действия), vm (модель представления), nap (предикат следующего действия) и S (представление состояния) являются и должны быть чистыми функциями. В SAM то, что мы обычно называем «состоянием» (значения свойств системы), полностью ограничено моделью, и логика, которая изменяет эти значения, не видна за пределами самой модели.

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

рис.6. Шаблон «Состояние-Действие-Режим» (SAM)

Сам по себе шаблон не зависит от какого-либо протокола (и может быть без труда реализован через HTTP) и любой топологии клиент / сервер.

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

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

Ключевым преимуществом этого нового шаблона является то, что он четко отделяет операции CRUD от действий. Модель отвечает за ее постоянство, которое будет реализовано с помощью операций CRUD, недоступных из представления. В частности, представление никогда не будет в состоянии «извлекать» данные, единственное, что может делать представление, — это запрашивать представление текущего состояния системы и инициировать реактивный поток, инициируя действия.

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

Вот как будет реализовано действие «Изменение адреса», вызывающее API проверки адреса:

(Щелкните изображение, чтобы увеличить его)

рис.7. реализация «Смена адреса»

Элементы шаблона, действия и модели могут быть составлены произвольно:

Функциональная композиция

данные ’= A (B (данные))

Состав коллег (одинаковый набор данных представлен для двух моделей)

M1.present (данные)

M2.present (данные)

Состав родитель-потомок (родительская модель управляет набором данных, представленным дочернему элементу)

М1.присутствует (данные ’, M2)

функция присутствует (данные, потомок) {

// выполняем обновления

// синхронизация моделей

дитя. Настоящее (c (данные))

}

Состав публикации / подписки

M1.on («тема», настоящее время)

M2.on («тема», настоящее время)

или

M1.on («данные», настоящее время)

M2.on («данные», настоящее время)

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

рис 8. Модель состава SAM

Весь шаблон сам по себе является составным, и вы можете реализовать экземпляр SAM, работающий в браузере, чтобы поддерживать поведение, подобное мастеру (например, приложение ToDo), взаимодействуя с экземпляром SAM на сервере:

рис. 9 Экземплярный состав ЗРК

Обратите внимание, что внутренний экземпляр SAM доставляется как часть представления состояния, генерируемого внешним экземпляром.

Сеанс регидратации должен произойти до запуска действия (рис. 10). SAM обеспечивает интересную композицию, в которой представление может вызывать действие третьей стороны, предоставляя токен и обратный вызов, указывающий на действие системы, которое авторизует и проверяет вызов, прежде чем представлять данные модели.

рис. 10 Управление сеансом с SAM

С точки зрения CQRS, шаблон не делает особого различия между запросами и командами, хотя базовая реализация должна делать это различие.[a] $ / i ’} // Имена, начинающиеся с A или

 {_customerId: ‘123’} // клиент с id = 123 

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

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

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

Реактивная и функциональная структура шаблона упрощает воспроизведение и модульное тестирование.

Шаблон SAM полностью меняет парадигму интерфейсных архитектур, поскольку на основе TLA + бизнес-логика может быть четко разделена на:

  • Действия как чистые функции
  • CRUD операций в модели
  • Состояния, управляющие автоматическими действиями

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

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

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

Самое главное, что шаблон, как и React, не требует привязки данных или шаблона.

Я ожидаю, что со временем SAM внесет свой вклад в то, чтобы виртуальный дом стал постоянной функцией браузера, а новые представления состояний будут напрямую обрабатываться через специальный API.

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

Я хотел поблагодарить и поблагодарить людей, любезно согласившихся рассмотреть эту статью: профессора Жана Безивина, профессора Жоэль Коутаз, Браулио Диеса, Адрона Холла, Эдвина Ходабаккиана, Гийома Лафоржа, Педро Молина, Арнона Ротем-Гал-Оз.

Об авторе

Жан-Жак Дубре — основатель xgen.io и gliiph. Он строил сервис-ориентированные архитектуры и платформы API в течение последних 15 лет.Он является бывшим членом исследовательского персонала HRL и имеет степень доктора философии. из Университета Прованса (кампус Luminy), родины языка Пролог. Он является изобретателем методологии BOLT.

Лучшие фреймворки JavaScript MVC

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

  • Backbone.js: предоставляет модели с привязкой «ключ-значение» и настраиваемыми событиями, коллекциями и подключает все это к существующему API через интерфейс RESTful JSON.
  • AngularJS: набор инструментов, основанный на расширении словаря HTML для вашего приложения.
  • Ember.js: предоставляет шаблон, написанный на языке шаблонов Handlebars, представления, контроллеры, модели и маршрутизатор.
  • Knockout: направлен на упрощение пользовательских интерфейсов JavaScript путем применения шаблона модель-представление-представление (MVVM).
  • Agility.js: нацелен на то, чтобы позволить разработчикам писать обслуживаемый и повторно используемый код браузера без подробных или инфраструктурных накладных расходов, присущих другим библиотекам MVC.
  • CanJS: нацелен на достижение баланса между размером, простотой использования, безопасностью, скоростью и гибкостью.
  • Spine: легкий фреймворк, который стремится иметь максимально удобную документацию для любого доступного фреймворка JavaScript.
  • Мария: Основана на оригинальном варианте MVC, который использовался в Smalltalk — он же «Банда четырех MVC».
  • ExtJS: среди прочего предлагает создание диаграмм без плагинов и современные виджеты пользовательского интерфейса.
  • Sammy.js: небольшой фреймворк JavaScript, разработанный для обеспечения базовой структуры для разработки приложений JavaScript.
  • Stapes.js: крошечный фреймворк, который стремится легко вписаться в существующую кодовую базу, и из-за своего размера он подходит для мобильной разработки.
  • Epitome: Epitome — это фреймворк MVC * (MVP) для MooTools.
  • soma.js: пытается помочь разработчикам писать слабосвязанные приложения для повышения масштабируемости и удобства обслуживания.
  • PlastronJS: среда MVC для библиотеки закрытия и компилятора закрытия.
  • rAppid.js: позволяет инкапсулировать сложность в компоненты, которые можно легко использовать, как элементы HTML, в вашем приложении.
  • Serenade.js: пытается следовать идеям классического MVC, а не конкурирующих фреймворков.
  • Kendo UI: объединяет виджеты на основе jQuery, структуру MVVM, темы, шаблоны и многое другое.

10 лучших фреймворков JavaScript MVC

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

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

Фреймворки

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

Что такое JavaScript MVC Framework?

Шаблон «Модель-Представление-Контроллер» помогает разработчикам организовать свой код в лаконичной и доступной форме. Эти три элемента можно очень просто описать следующим образом:

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

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

Лучшие фреймворки JavaScript MVC

HTML-приложения Ajax становятся все более изощренными, но разработчикам требуется помощь, чтобы в полной мере воспользоваться преимуществами современных веб-браузеров. К счастью, доступен широкий спектр фреймворков JavaScript MVC. Ниже мы выбрали 10 лучших.

1. Kendo
Отличный фреймворк для разработки мобильных и веб-приложений, состоящий из трех виджетов: UI Web (все, что вам нужно для создания современного веб-сайта), UI Mobile (предлагает возможность создавать мобильные веб-приложения, которые могут быть ошибочно приняты за нативные). apps) и UI DataVis (позволяет разработчикам реализовать красивую визуализацию данных и отчетов, ориентированную на пользователя).

2. Sencha Touch
Sencha — отличная библиотека JavaScript пользовательского интерфейса, созданная специально для мобильных веб-приложений и позволяющая разработчикам создавать пользовательский интерфейс, похожий на нативные приложения.

3. jQuery Mobile
Кросс-платформенная мобильная среда JavaScript, jQuery Mobile, предназначена для улучшения и упрощения разработки веб-приложений за счет интеграции HTML5, jQuery, CSS и пользовательского интерфейса jQuery в одну единую структуру. Он надежен и хорошо организован.

4. AngularJS
Многие считают, что это «большой папа» фреймворков JavaScript, так как он был разработан Google. За AngularJS стоит огромное сообщество разработчиков, и он особенно выделяется в части расширения кода HTML благодаря своей способности помогать в создании динамических пользовательских интерфейсов.

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

6. Backbone
Платформа Backbone, используемая Pinterest, Walmart и Delicious, целенаправленно проста, легка в освоении и легка в развертывании. Многим разработчикам нравится легкость, с которой Backbone.js можно вставить в любой проект.

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

8. React
Facebook и Instagram полагаются на фреймворк React JavaScript из-за его способности создавать большие динамические приложения, которые можно значительно масштабировать. React показывает лучшие результаты при рендеринге сложных пользовательских интерфейсов и быстро становится самым быстрорастущим фреймворком JavaScript современности.

9. Aurelia
Относительно молодой фреймворк Aurelia был первоначально выпущен в январе 2015 года, и его корни уходят в AngularJS. Он примечателен своей обширной коллекцией небольших библиотек, из которых разработчики могут выбирать без необходимости реализовывать весь фреймворк.

10. Полимер
Еще одно изобретение Google. Фреймворк Polymer расширяет возможности HTML-кода за счет использования веб-компонентов. Это означает, что стандартные элементы HTML5 можно настраивать (например,

Примечание о кроссплатформенной разработке

Сейчас на рынке так много устройств и операционных систем, что разработчики требуют простых способов создания приложений с использованием технологии HTML5. К счастью, ряд платформ делает кроссплатформенную разработку в высшей степени доступной. Sencha Touch и jQuery Mobile упомянуты выше, но PhoneGap и NativeScript также терпят поражение.

Сводка

Любой достойный разработчик знает ценность фреймворков в программировании на JavaScript.Можно потерять бесчисленные часы, переписывая код, который является скорее функциональным, чем творческим, или нацеленным на реализацию бизнес-логики приложения. Такой код жизненно важен, но фреймворки MVC упрощают кропотливую работу по его реализации.

Хотите узнать больше? См. Нашу страницу о веб-разработке >>

Архитектура

MVC — разработчики Chrome

Важно: Chrome прекращает поддержку приложений Chrome на всех платформах. Браузер Chrome и Интернет-магазин Chrome продолжат поддерживать расширения. Прочтите объявление и узнайте больше о , переносящем приложение на .

По мере того, как современные браузеры становятся все более мощными с богатыми функциями, создание полноценных веб-приложений на JavaScript не только возможно, но и становится все более популярным. Судя по тенденциям в HTTP Archive, размер развернутого кода JavaScript за год вырос на 45%.

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

Шаблоны проектирования важны для написания поддерживаемого и многократно используемого кода. Шаблон — это многоразовое решение, которое можно применить к часто возникающим проблемам при разработке программного обеспечения — в нашем случае — при написании приложений Chrome. Мы рекомендуем разработчикам разделить приложение на серию независимых компонентов по шаблону MVC.

За последние несколько лет был разработан ряд фреймворков JavaScript MVC, таких как backbone.js, ember.js, AngularJS, Sencha, Kendo UI и другие. Хотя все они имеют свои уникальные преимущества, каждый из них следует некоторой форме шаблона MVC с целью поощрения разработчиков к написанию более структурированного кода JavaScript.

Обзор шаблона MVC #

MVC предлагает архитектурные преимущества по сравнению со стандартным JavaScript — он помогает писать более организованный и, следовательно, более удобный в сопровождении код.Этот шаблон использовался и тщательно тестировался на нескольких языках и поколениями программистов.

MVC состоит из трех компонентов:

Модель №

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

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

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

View #

View — это то, что предоставляется пользователям и как пользователи взаимодействуют с приложением. Представление создается с помощью HTML, CSS, JavaScript и часто шаблонов. Эта часть вашего приложения Chrome имеет доступ к модели DOM.

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

Контроллер #

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

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

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

Если вы хотите узнать больше, мы рекомендуем онлайн-книгу Адди Османи: Learning JavaScript Design Patterns.

Подводя итог, шаблон MVC предоставляет разработчикам приложений модульность и позволяет:

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

Шаблоны сохраняемости MVC #

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

Модель выполняет свою собственную персистентность — шаблон ActiveRecord #

Популярный как в серверных фреймворках, таких как Ruby on Rails, так и в клиентских фреймворках, таких как Backbone.js и ember.js, шаблон ActiveRecord возлагает ответственность за постоянство на модель сам по себе и обычно реализуется через JSON API.

Использование персистентности немного отличается от описания дескриптора модели — это введение отдельной концепции Store и Adapter API.Магазин, Модель и Адаптер (в некоторых фреймворках это называется Прокси) работают вручную. Хранилище — это репозиторий, в котором хранятся загруженные модели, а также он предоставляет такие функции, как создание, запрос и фильтрация экземпляров модели, содержащихся в нем.

Адаптер или прокси-сервер получает запросы из хранилища и преобразует их в соответствующие действия, которые необходимо предпринять в отношении вашего постоянного уровня данных (например, JSON API). Это интересно в дизайне современного веб-приложения, потому что вы часто взаимодействуете с более чем одним постоянным уровнем данных, например с удаленным сервером и локальным хранилищем браузера.Приложения Chrome предоставляют как Chrome Storage API, так и API файловой системы HTML 5 для хранения на стороне клиента.

Плюсы:

  • Простой в использовании и понимании.

Минусы:

  • Трудно протестировать, поскольку уровень сохраняемости «запечен» в иерархии объектов.
  • Сложно заставить разные объекты использовать разные постоянные хранилища (например, API файловой системы против indexedDB или на стороне сервера).
  • Повторное использование модели в других приложениях может вызвать конфликты, такие как совместное использование одного класса Customer между двумя разными представлениями, причем каждое представление желает сохранить в разных местах.

Контроллер поддерживает постоянство #

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

Плюсы:

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

Минусы:

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

AppController выполняет постоянство #

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

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

Плюсы:

  • Перемещает уровень сохраняемости еще выше по стеку, где его можно легко изменить.
  • Не загрязняет контроллеры нижнего уровня, такие как DatePickerController, необходимостью знать о постоянстве.

Минусы:

  • Каждая «страница / экран» приложения теперь требует большого количества шаблонов для написания или обновления: Model, View, Controller, AppController.

Рекомендуемые фреймворки MVC #

MVC имеет решающее значение для разработки приложений Chrome.Мы рекомендуем следующие CSP-совместимые платформы MVC для написания безопасных и масштабируемых приложений Chrome:

Полезные ресурсы #

Интернет #

Книги #

MVC — Глоссарий веб-документов MDN: определения терминов, связанных с Интернетом

MVC (Модель-Представление-Контроллер) — это шаблон в разработке программного обеспечения, обычно используемый для реализации пользовательских интерфейсов, данных и управляющей логики. Он подчеркивает разделение бизнес-логики программного обеспечения и отображения. Такое «разделение ответственности» обеспечивает лучшее разделение труда и улучшенное обслуживание.Некоторые другие шаблоны проектирования основаны на MVC, например MVVM (Model-View-Viewmodel), MVP (Model-View-Presenter) и MVW (Model-View-Whatever).

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

  1. Модель: управляет данными и бизнес-логикой.
  2. View: обрабатывает макет и отображение.
  3. Контроллер
  4. : направляет команды к модели и просматривает детали.

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

Модель

Модель определяет, какие данные должно содержать приложение. Если состояние этих данных изменяется, то модель обычно уведомляет представление (так что отображение может изменяться по мере необходимости), а иногда и контроллер (если для управления обновленным представлением требуется другая логика).

Возвращаясь к нашему приложению со списком покупок, модель должна указывать, какие данные должны содержать элементы списка — товар, цена и т. Д.- и какие элементы списка уже присутствуют.

Представление

Представление определяет, как должны отображаться данные приложения.

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

Контроллер

Контроллер содержит логику, которая обновляет модель и / или представление в ответ на ввод от пользователей приложения.

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

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

Как веб-разработчик, этот шаблон, вероятно, будет хорошо знаком, даже если вы никогда раньше не использовали его сознательно.Ваша модель данных, вероятно, содержится в какой-то базе данных (будь то традиционная серверная база данных, такая как MySQL, или решение на стороне клиента, такое как IndexedDB [en-US].) Управляющий код вашего приложения, вероятно, написан на HTML / JavaScript. , и ваш пользовательский интерфейс, вероятно, написан с использованием HTML / CSS / любого другого, что вам нравится. Это очень похоже на MVC, но MVC заставляет эти компоненты следовать более жесткому шаблону.

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

Все веб-фреймворки

, такие как AngularJS и Ember.js, реализуют архитектуру MVC, хотя и немного по-разному.

Общие знания

Использование JavaScript с частичными представлениями Ajax и Razor | Pluralsight

  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 год
22
23
24
25
26 год
27
28 год
29
30
31 год
32
33
34
35 год
36
37
38
39
40
41 год
42
43 год
44 год
45
46
47
48
49
50
51
52   @model Blip.Entities.Customers.ViewModels.CustomerEditViewModel  @ {
 Layout = null;
}  @using (Html.BeginForm ("EditCustomerPartial", "Клиент", FormMethod.Post))
{
 @ Html.AntiForgeryToken ()
<час />
Редактировать данные о клиенте
@ Html.ValidationSummary (true, "", новый {@class = "text-dangerous"})
@ Html.LabelFor (model => model.CustomerID, htmlAttributes: new {@class = "control-label col-md-2"})
@Html.EditorFor (model => model.CustomerID, new {htmlAttributes = new {@class = "form-control", @readonly = "readonly"}})
@ Html.LabelFor (model => model.CustomerName, htmlAttributes: new {@class = "control-label col-md-2"})
@ Html.EditorFor (model => model.CustomerName, new {htmlAttributes = new {@class = "form-control"}}) @ Html.ValidationMessageFor (модель => модель.CustomerName, "", новый {@class = "text-dangerous"})
@ Html.LabelFor (model => model.SelectedCountryIso3, htmlAttributes: new {@class = "control-label col-md-2"})
@ Html.DropDownListFor (model => model.SelectedCountryIso3, new SelectList (Model.Countries, "Value", "Text"), htmlAttributes: new {@class = "form-control", @ id = "Country"}) @ Html.