AngularJS: понимание шаблона проектирования


в контексте этот пост Игорь Минар, ведущий AngularJS:

MVC vs MVVM vs MVP. Какая спорная тема, что многие разработчики может часами спорить и спорить об этом.

в течение нескольких лет AngularJS был ближе к MVC (или, скорее, один из его клиентские вариантов), но с течением времени и благодаря множеству рефакторинга и улучшения api, теперь он ближе к MVVM - the $ scope объект можно было бы считать ViewModel который украшается a функция, которую мы называем контроллер.

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

сказав, Я бы предпочел, чтобы разработчики создавали надрывные приложения, которые хорошо продумайте и проследите за разделением забот, чем увидите их отходы время спорить о МВ * ерунда. И по этой причине я объявляю AngularJS на mvw framework-Model-View-Whatever. Где Все расшифровывается как"если вы".

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

существуют ли какие-либо рекомендации или рекомендации по реализации шаблона проектирования AngularJS MVW (Model-View-Whatever) в клиентских приложениях?

5 146

5 ответов:

благодаря огромному количеству ценных источников у меня есть некоторые общие рекомендации по реализации компонентов в приложениях AngularJS:


контроллер

  • контроллер должен быть просто прослойка между моделью и видом. Попробуйте сделать это как тонкий как это возможно.

  • рекомендуется избежать бизнес-логики в контроллер. Он должен быть перемещен в модель.

  • контроллер может взаимодействовать с другими контроллерами с помощью вызова метода (возможно, когда дети хотят общаться с родителем) или $emit, $ broadcast и $on методы. Излучаемые и транслируемые сообщения должны быть сведены к минимуму.

  • на $rootScope и привязать его к commonModel во время начальной загрузки приложения:
    angular.module('app', ['app.common'])
    .config(...)
    .run(['$rootScope', 'commonModel', function ($rootScope, commonModel) {
      $rootScope.common = 'commonModel';
    }]);

    все ваши глобальные методы будут жить в ‘common’. Это какой-то пространство имен.

    но не определяйте никаких методов непосредственно в вашем $rootScope. Это может привести к неожиданное поведение при использовании с директивой ngModel в пределах области видимости, как правило, засоряет область и приводит к методам области перекрывающие вопросы.


    ресурс

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

    должно быть реализовано с помощью принцип единой ответственности.

    в частном случае это многоразовые прокси для конечных точек HTTP/JSON.

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

    ресурс реализация

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

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


    услуги

    как модель, так и ресурс являются услугами.

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

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

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

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

    попробуйте рассмотреть основные принципы архитектуры в вашем приложении.

    В общем по Web-Сервисы Глоссарий:

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


    структура на стороне клиента

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

    попробуйте определить модули в зависимости от функции/возможности или view, а не по типу. Смотрите презентация Миско для сведения.

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

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

    разработчикам также намного проще найти некоторые части кода и все его зависимости.

    пожалуйста, обратитесь к организация кода в больших приложениях AngularJS и JavaScript для сведения.

    пример папки структурирование:

    |-- src/
    |   |-- app/
    |   |   |-- app.js
    |   |   |-- home/
    |   |   |   |-- home.js
    |   |   |   |-- homeCtrl.js
    |   |   |   |-- home.spec.js
    |   |   |   |-- home.tpl.html
    |   |   |   |-- home.less
    |   |   |-- user/
    |   |   |   |-- user.js
    |   |   |   |-- userCtrl.js
    |   |   |   |-- userModel.js
    |   |   |   |-- userResource.js
    |   |   |   |-- user.spec.js
    |   |   |   |-- user.tpl.html
    |   |   |   |-- user.less
    |   |   |   |-- create/
    |   |   |   |   |-- create.js
    |   |   |   |   |-- createCtrl.js
    |   |   |   |   |-- create.tpl.html
    |   |-- common/
    |   |   |-- authentication/
    |   |   |   |-- authentication.js
    |   |   |   |-- authenticationModel.js
    |   |   |   |-- authenticationService.js
    |   |-- assets/
    |   |   |-- images/
    |   |   |   |-- logo.png
    |   |   |   |-- user/
    |   |   |   |   |-- user-icon.png
    |   |   |   |   |-- user-default-avatar.png
    |   |-- index.html

    хороший пример углового структурирования приложения реализован angular-app - https://github.com/angular-app/angular-app/tree/master/client/src

    Это также учитывается современными генераторами приложений -https://github.com/yeoman/generator-angular/issues/109

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

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

давайте сделаем это по крупицам.

руководство

вид

в угловом контексте вид является DOM. Руководящие принципы:

Do:

  • присутствует переменная (только чтение).
  • вызовите контроллер для действий.

нет:

  • поставить какой-либо логики.

как заманчиво, коротко, и безобидно это выглядит:

ng-click="collapsed = !collapsed"

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

контроллеры

Do:

  • свяжите представление с "моделью", поместив данные в область видимости.
  • реагировать на действия пользователя.
  • дело с логикой представления.

нет:

  • интернет с любой бизнес-логикой.

причина последнего руководства заключается в том, что контроллеры являются сестрами для представлений, а не сущностями; и они не являются многоразовыми.

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

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

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

таким образом, контроллеры в Angular действительно больше Модель Презентации или MVVM.

и так, если контроллеры не должны иметь дело с бизнес-логикой, кто должен?

что такое a модель?

ваша клиентская модель часто является частичной и устаревшей

если вы не пишете автономное веб-приложение или приложение, которое ужасно просто (несколько объектов), ваша клиентская модель, скорее всего, будет:

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

реальная модель должна сохраняться

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

последствия

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

таким образом, возможно, разумно в контексте клиента использовать нижний регистр M - так это правда mVC,mVP и mVVm. Большой M для сервер.

бизнес-логики

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

  • логика или бизнес-правила предприятия, логика, которая не зависит от приложения. Например, дайте модель с firstName и sirName свойства геттера как getFullName() можно считать независимым от приложения.
  • логика приложения или бизнес-правила приложения, который является специфичным для приложения. Например, проверка и обработка ошибок.

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

вопрос все еще остается - где вы бросаете их в угловом приложении?

3 против 4 уровня архитектуры

все эти рамки MVW используют 3 слоя:

Three circles. Inner - model, middle - controller, outer - view

но есть две фундаментальные проблемы с этим, когда дело доходит для клиентов:

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

альтернативой этой стратегии является стратегия 4 слоя:

4 circles, from inner to outer - Enterprise business rules, Application business rules, Interface adapters, Frameworks and drivers

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

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

конкретный пример

рассмотрим следующее веб-приложение:

  • приложение показывает разбитый на страницы список пользователей.
  • пользователь нажимает кнопку 'Добавить пользователя'.
  • откроется модель с формой для заполнения сведений о пользователе.
  • пользователь заполняет форму и нажимает кнопку Отправить.

несколько вещей должно произойти теперь:

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

куда мы все это бросим?

если ваша архитектура включает контроллер, который вызывает $resource, все это будет происходить в контроллере. Но есть и получше стратегия.

предложенное решение

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

4 boxes - DOM points to Controller, which points to Application logic, which points to $resource

поэтому мы добавляем слой между контроллером в $resource, этот слой (назовем его interactor):

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

и так, с требования конкретного примера выше:

  • пользователь нажимает кнопку 'Добавить пользователя'.
  • контроллер запрашивает у интерактора пустую модель пользователя, которая украшена методом бизнес-логики, например validate()
  • после представления контроллер вызывает модель validate() метод.
  • если не удалось, контроллер обрабатывает ошибку.
  • в случае успеха контроллер вызывает interactor с помощью createUser()
  • в interactor вызывает $resource
  • после ответа, interactor делегирует любые ошибки контроллеру, который обрабатывает их.
  • после успешного ответа, interactor гарантирует, что при необходимости, список пользователей обновляется.

незначительная проблема по сравнению с большими советами в ответе Артема, но с точки зрения читаемости кода я нашел лучше всего определить API полностью внутри return объект, чтобы свести к минимуму переход туда и обратно в коде, чтобы посмотреть wheverer переменные определены:

angular.module('myModule', [])
// or .constant instead of .value
.value('myConfig', {
  var1: value1,
  var2: value2
  ...
})
.factory('myFactory', function(myConfig) {
  ...preliminary work with myConfig...
  return {
    // comments
    myAPIproperty1: ...,
    ...
    myAPImethod1: function(arg1, ...) {
    ...
    }
  }
});

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

в AngularJS делаешь не внедрить MVC в традиционный способ, а он реализует что-то ближе к шаблон MVVM(модель-представление-модель представления), модель представления может также рассматриваться как связующее(в угловой шкаф, он может быть $охвата). Модель--> как мы знаем модель в angular может быть просто старые объекты JS или данные в нашем приложении

представление--> представление в angularJS-это HTML, который был проанализирован и скомпилирован angularJS путем применения директив или инструкций или Привязок, главное здесь в angular вход-это не просто простая строка HTML (innerHTML), а DOM, созданный браузером.

ViewModel--> ViewModel на самом деле является связующим/мостом между вашим представлением и моделью в случае angularJS это $scope, для инициализации и увеличения $scope мы используем контроллер.

Если я хочу обобщить ответ: в приложении angularJS $scope есть ссылка на данные, контроллер управляет поведением, а представление обрабатывает макет, взаимодействуя с контроллер должен вести себя соответственно.

чтобы быть четким в вопросе, Angular использует различные шаблоны проектирования, с которыми мы уже сталкивались в нашем регулярном программировании. 1) Когда мы регистрируем наши регуляторы или директивы, фабрику, обслуживания etc по отношению к нашему модулю. Здесь он скрывает данные из глобального пространства. А это модуль pattern. 2) когда angular использует свою грязную проверку для сравнения переменных области, здесь он использует Шаблон Observer. 3) все родительские дочерние области в нашем контроллеры использует прототипная модель. 4) в случае введения услуг, которые он использует Шаблон Фабрики.

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