В контексте этого поста Игорь Минар, ведущий AngularJS:
MVC против MVVM против MVP . Что за спорная тема, о которой многие разработчики могут часами спорить и спорить.
В течение нескольких лет AngularJS был ближе к MVC (или, скорее, к одному из его вариантов на стороне клиента), но со временем и благодаря множеству рефакторингов и улучшений API теперь он ближе к MVVM - объект $ scope можно рассматривать как модель ViewModel, которая сейчас украшен функцией, которую мы называем контроллером .
Возможность классифицировать фреймворк и поместить его в одну из групп MV * имеет некоторые преимущества. Он может помочь разработчикам освоиться с его API-интерфейсом, упрощая создание ментальной модели, представляющей приложение, которое создается с помощью фреймворка. Это также может помочь установить терминологию, которая используется разработчиками.
Сказав это, я бы предпочел, чтобы разработчики создавали офигенные приложения, которые были бы хорошо спроектированы и следили за разделением интересов, чем видел, как они тратят время на споры о бессмысленности MV *. И по этой причине, я заявляю AngularJS быть MVW рамки - Model-View-Безотносительно . Где Что бы ни означало « все, что работает для вас ».
Angular дает вам большую гибкость, чтобы красиво отделить логику представления от бизнес-логики и состояния представления. Пожалуйста, используйте его, чтобы повысить производительность и удобство обслуживания приложений, а не горячие дискуссии о вещах, которые в конце концов не так важны.
Существуют ли какие-либо рекомендации или рекомендации по внедрению шаблона проектирования AngularJS MVW (модель-вид-что-либо) в клиентские приложения?
источник
Ответы:
Благодаря огромному количеству ценных источников я получил несколько общих рекомендаций по реализации компонентов в приложениях AngularJS:
контроллер
Контроллер должен быть просто прослойкой между моделью и видом. Постарайтесь сделать его максимально тонким .
Настоятельно рекомендуется избегать бизнес-логики в контроллере. Следует перенести в модель.
Контроллер может связываться с другими контроллерами, используя вызов метода (возможно, когда дети хотят общаться с родителем) или методы $ emit , $ broadcast и $ on . Передаваемые и передаваемые сообщения должны быть сведены к минимуму.
Контроллер не должен заботиться о представлении или манипулировании DOM.
Старайтесь избегать вложенных контроллеров . В этом случае родительский контроллер интерпретируется как модель. Вместо этого введите модели как общие службы.
Область применения контроллера должен использоваться для связывания модели с учетом и
герметизирующего View Model , как для представления модели шаблона проектирования.
Объем
Обрабатывать область видимости только для чтения в шаблонах и только для записи в контроллерах . Цель этой области - обратиться к модели, а не к модели.
При выполнении двунаправленной привязки (ng-model) убедитесь, что вы не привязываете напрямую к свойствам области.
Модель
Модель в AngularJS является одноэлементной, определяемой сервисом .
Модель предоставляет отличный способ разделения данных и отображения.
Модели являются основными кандидатами для модульного тестирования, поскольку они обычно имеют ровно одну зависимость (некоторую форму генератора событий, в общем случае $ rootScope ) и содержат хорошо проверяемую логику домена .
Модель следует рассматривать как реализацию конкретной единицы. Он основан на принципе единой ответственности. Модуль - это экземпляр, который отвечает за собственную область связанной логики, которая может представлять отдельную сущность в реальном мире и описывать ее в мире программирования с точки зрения данных и состояния .
Модель должна инкапсулировать данные вашего приложения и предоставлять API для доступа к этим данным и манипулирования ими.
Модель должна быть портативной, чтобы ее можно было легко транспортировать в аналогичное приложение.
Выделив логику модуля в своей модели, вы упростили поиск, обновление и обслуживание.
Модель может использовать методы более общих глобальных моделей, которые являются общими для всего приложения.
Старайтесь избегать встраивания других моделей в вашу модель, используя внедрение зависимостей, если это на самом деле не зависит от уменьшения связи компонентов и повышения тестируемости и удобства использования .
Старайтесь избегать использования слушателей событий в моделях. Это затрудняет их тестирование и в целом убивает модели с точки зрения принципа единой ответственности.
Реализация модели
Поскольку модель должна инкапсулировать некоторую логику с точки зрения данных и состояния, она должна архитектурно ограничивать доступ к своим членам, поэтому мы можем гарантировать слабую связь.
Способ сделать это в приложении AngularJS - определить его, используя тип сервиса фабрики . Это позволит нам очень легко определять частные свойства и методы, а также возвращать общедоступные в одном месте, что сделает его действительно читабельным для разработчика.
Пример :
Создание новых экземпляров
Старайтесь избегать фабрики, которая возвращает новую функциональную функцию, поскольку это начинает ломать внедрение зависимостей, и библиотека будет вести себя неловко, особенно для третьих лиц.
Лучший способ сделать то же самое - использовать фабрику как API для возврата коллекции объектов с прикрепленными к ним методами getter и setter.
Глобальная модель
В общем, старайтесь избегать таких ситуаций и правильно проектируйте свои модели, чтобы их можно было вводить в контроллер и использовать по вашему мнению.
В частном случае некоторые методы требуют глобальной доступности в приложении. Чтобы сделать это возможным, вы можете определить « общее » свойство в $ rootScope и связать его с commonModel во время начальной загрузки приложения:
Все ваши глобальные методы будут жить в рамках « общего » свойства. Это какое-то пространство имен .
Но не определяйте какие-либо методы непосредственно в вашем $ rootScope . Это может привести к неожиданному поведению при использовании с директивой ngModel в вашей области видимости, как правило, засоряет вашу область и приводит к тому, что методы области переопределяют проблемы.
Ресурс
Ресурс позволяет вам взаимодействовать с различными источниками данных .
Должно быть реализовано с использованием принципа единой ответственности .
В частном случае это повторно используемый прокси для конечных точек HTTP / JSON.
Ресурсы внедряются в модели и предоставляют возможность отправлять / извлекать данные.
Реализация ресурсов
Фабрика, которая создает объект ресурса, который позволяет вам взаимодействовать с RESTful-источниками данных на стороне сервера.
Возвращенный объект ресурса имеет методы действия, которые обеспечивают высокоуровневое поведение без необходимости взаимодействия со службой $ http низкого уровня.
Сервисы
И модель, и ресурс являются услугами .
Сервисы - это несвязанные, слабо связанные блоки функциональности, которые являются автономными.
Сервисы - это функция, которую Angular предоставляет клиентским веб-приложениям со стороны сервера, где сервисы обычно используются в течение длительного времени.
Службы в приложениях Angular являются заменяемыми объектами, которые связаны друг с другом с помощью внедрения зависимостей.
Angular поставляется с различными видами услуг. Каждый со своими вариантами использования. Пожалуйста, прочитайте Понимание типов услуг для деталей.
Попробуйте рассмотреть основные принципы архитектуры сервиса в вашем приложении.
В целом, согласно Глоссарию веб-сервисов :
Клиентская структура
В целом клиентская часть приложения разбита на модули . Каждый модуль должен быть тестируемым как единое целое.
Попробуйте определить модули в зависимости от функции / функциональности или вида , а не по типу. Смотрите презентацию Миско для деталей.
Компоненты модуля могут быть условно сгруппированы по типам, таким как контроллеры, модели, представления, фильтры, директивы и т. Д.
Но сам модуль остается многоразовым , передаваемым и тестируемым .
Разработчикам также намного проще найти некоторые части кода и все его зависимости.
Пожалуйста, обратитесь к организации кода в больших AngularJS и JavaScript приложений для деталей.
Пример структурирования папок :
Хороший пример структурирования угловых приложений реализован в angular-app - https://github.com/angular-app/angular-app/tree/master/client/src
Это также учитывается современными генераторами приложений - https://github.com/yeoman/generator-angular/issues/109
источник
searchModel
не следует совету по повторному использованию. Было бы лучше импортировать константы черезconstant
сервис. 3. Любое объяснение, что здесь подразумевается ?:Try to avoid having a factory that returns a new able function
prototype
свойства объекта нарушает наследование, вместо этого можно использоватьCar.prototype.save = ...
object
в вашем выражении двустороннего связывания, чтобы убедиться, что вы пишете точное свойство илиsetter
функцию. В случае использования прямого свойства вашей области ( без точки ) вы рискуете скрыть желаемое целевое свойство с недавно созданным в ближайшей верхней области в цепочке прототипов при записи в него. Это лучше объяснить в презентации МискоЯ полагаю, что взгляд Игоря на это, как видно из приведенной вами цитаты, является лишь верхушкой айсберга гораздо более серьезной проблемы.
MVC и его производные (MVP, PM, MVVM) все хороши и хороши в одном агенте, но архитектура сервер-клиент для всех целей является системой с двумя агентами, и люди часто настолько одержимы этими шаблонами, что забывают, что проблема под рукой гораздо сложнее. Пытаясь придерживаться этих принципов, они фактически получают ошибочную архитектуру.
Давайте сделаем это по крупицам.
Руководящие принципы
Просмотры
В контексте Angular представление является DOM. Руководящие принципы:
Делать:
Не рекомендуется:
Как заманчиво, коротко и безобидно это выглядит:
Любой разработчик в значительной степени показывает, что теперь, чтобы понять, как работает система, им нужно проверять как файлы Javascript, так и файлы HTML.
Контроллеры
Делать:
Не рекомендуется:
Причина последнего указания заключается в том, что контроллеры являются сестрами для представлений, а не сущностей; и они не могут быть использованы повторно.
Можно утверждать, что директивы можно использовать повторно, но директивы также являются сестрами представлений (DOM) - они никогда не предназначались для соответствия сущностям.
Конечно, иногда представления представляют сущности, но это довольно специфический случай.
Другими словами, контроллеры должны сосредоточиться на представлении - если вы добавите бизнес-логику, вы не только получите в результате раздутый, плохо управляемый контроллер, но и нарушите принцип разделения интересов .
Таким образом, контроллеры в Angular - это скорее Презентационная модель или MVVM .
И так, если контроллеры не должны иметь дело с бизнес-логикой, кто должен?
Что такое модель?
Ваша модель клиента часто является частичной и устаревшей
Если вы не пишете автономное веб-приложение или ужасно простое приложение (несколько сущностей), ваша модель клиента, скорее всего, будет:
Настоящая модель должна сохраняться
В традиционном MCV модель - единственное, что сохраняется . Всякий раз, когда мы говорим о моделях, они должны быть сохранены в какой-то момент. Ваш клиент может манипулировать моделями по своему усмотрению, но до тех пор, пока обратное обращение к серверу не будет успешно выполнено, работа не будет выполнена.
последствия
Два вышеприведенных пункта должны служить предупреждением - модель, которую использует ваш клиент, может включать только частичную, в основном простую бизнес-логику.
Поэтому в контексте клиента целесообразно использовать строчные буквы
M
- так что это действительно mVC , mVP и mVVm . БольшоеM
для сервера.Бизнес логика
Возможно, одна из самых важных концепций о бизнес-моделях заключается в том, что вы можете разделить их на 2 типа (я опускаю третий вид бизнес-модели, поскольку это история для другого дня):
firstName
иsirName
свойствами, геттер , какgetFullName()
можно считать приложение-независимым.Важно подчеркнуть, что оба они в контексте клиента не являются «реальной» бизнес-логикой - они имеют дело только с той частью, которая важна для клиента. Прикладная логика (не доменная логика) должна нести ответственность за облегчение связи с сервером и большую часть взаимодействия с пользователем; в то время как логика предметной области в основном мелкая, специфичная для сущности и управляемая представлением.
Вопрос все еще остается - куда вы кидаете их в угловое приложение?
3 против 4 уровня архитектуры
Все эти MVW фреймворки используют 3 слоя:
Но есть две фундаментальные проблемы с этим, когда речь идет о клиентах:
Альтернативой этой стратегии является четырехуровневая стратегия :
Реальная сделка здесь - это слой бизнес-правил приложения (Варианты использования), который часто не работает для клиентов.
Этот уровень реализуется с помощью интеракторов (дядя Боб), который Мартин Фаулер называет уровнем обслуживания сценариев операций .
Конкретный пример
Рассмотрим следующее веб-приложение:
Несколько вещей должно произойти сейчас:
Куда мы все это бросаем?
Если ваша архитектура включает контроллер, который вызывает
$resource
, все это будет происходить внутри контроллера. Но есть лучшая стратегия.Предлагаемое решение
На следующей диаграмме показано, как решить вышеуказанную проблему, добавив еще один уровень логики приложения в клиентах Angular:
Итак, мы добавляем слой между контроллером в $ resource, этот слой (давайте назовем его интерактором ):
UserInteractor
.И так, с требованиями конкретного примера выше:
validate()
validate()
метод модели .createUser()
источник
Незначительная проблема по сравнению с замечательными советами в ответе Артема, но с точки зрения читабельности кода, я обнаружил, что лучше всего определить API полностью внутри
return
объекта, чтобы свести к минимуму переходы вперед и назад в коде для просмотра, где будут определены переменные:Если
return
объект выглядит «слишком людным», это признак того, что Сервис делает слишком много.источник
AngularJS не реализует MVC традиционным способом, скорее он реализует нечто более близкое к MVVM (Model-View-ViewModel), ViewModel также может называться связывателем (в угловом случае это может быть $ scope). Модель -> Как мы знаем, угловая модель может быть просто старыми объектами JS или данными в нашем приложении.
Представление -> представление в angularJS - это HTML-код, который был проанализирован и скомпилирован angularJS с применением директив, инструкций или привязок. Главное здесь в угловом вводе - это не просто простая строка HTML (innerHTML), а DOM создан браузером
ViewModel -> ViewModel на самом деле является связующим звеном / мостом между вашим представлением и моделью в случае angularJS, это $ scope, чтобы инициализировать и дополнить $ scope, которую мы используем Controller.
Если я хочу обобщить ответ: в приложении angularJS $ scope имеет ссылку на данные, Controller управляет поведением, а View обрабатывает макет, взаимодействуя с контроллером, чтобы вести себя соответствующим образом.
источник
Чтобы быть ясным в этом вопросе, Angular использует различные шаблоны проектирования, с которыми мы уже сталкивались в нашем обычном программировании. 1) Когда мы регистрируем наши контроллеры или директивы, фабрики, службы и т. Д. В отношении нашего модуля. Здесь скрываются данные из глобального пространства. Что является модульным шаблоном . 2) Когда angular использует свою грязную проверку для сравнения переменных области видимости, здесь он использует Observer Pattern . 3) Все родительские дочерние области в наших контроллерах используют шаблон Prototypal. 4) В случае внедрения сервисов он использует Factory Pattern .
В целом он использует различные известные шаблоны проектирования для решения проблем.
источник