AngularJS: Entwurfsmuster verstehen


147

Im Rahmen dieses Beitrags von Igor Minar, Leiter von AngularJS:

MVC gegen MVVM gegen MVP . Was für ein kontroverses Thema, über das viele Entwickler stundenlang diskutieren und streiten können.

AngularJS war mehrere Jahre näher an MVC (oder besser gesagt an einer seiner clientseitigen Varianten), aber im Laufe der Zeit und dank vieler Refactorings und API-Verbesserungen ist es jetzt näher an MVVM - das $ scope- Objekt könnte als das ViewModel betrachtet werden , das es gibt dekoriert durch eine Funktion, die wir einen Controller nennen .

Die Möglichkeit, ein Framework zu kategorisieren und in einen der MV * -Buckets zu legen, hat einige Vorteile. Es kann Entwicklern helfen, sich mit seiner API besser vertraut zu machen, indem es die Erstellung eines mentalen Modells erleichtert, das die Anwendung darstellt, die mit dem Framework erstellt wird. Es kann auch hilfreich sein, eine Terminologie festzulegen, die von Entwicklern verwendet wird.

Trotzdem würde ich lieber sehen, wie Entwickler umwerfende Apps entwickeln, die gut gestaltet sind und der Trennung von Bedenken folgen, als dass sie Zeit damit verschwenden, über MV * -Nonsens zu streiten. Aus diesem Grund erkläre ich AngularJS hiermit zum MVW-Framework - Model-View-Whatever . Wo was auch immer für " was auch immer für Sie funktioniert " steht.

Angular bietet Ihnen viel Flexibilität, um die Präsentationslogik von der Geschäftslogik und dem Präsentationsstatus zu trennen. Verwenden Sie es, um Ihre Produktivität und Wartbarkeit der Anwendung zu steigern, anstatt heftige Diskussionen über Dinge zu führen, die am Ende des Tages nicht so wichtig sind.

Gibt es Empfehlungen oder Richtlinien für die Implementierung des AngularJS MVW-Entwurfsmusters (Model-View-Whatever) in clientseitigen Anwendungen?


upvoted for ... als zu sehen, wie sie Zeit damit verschwenden, über MV * -Nonsens zu streiten.
Shirgill Farhan

1
Sie benötigen Angular nicht, um einem Wortklassen-Entwurfsmuster zu folgen.
nützlichBee

Antworten:


223

Dank einer Vielzahl wertvoller Quellen habe ich einige allgemeine Empfehlungen für die Implementierung von Komponenten in AngularJS-Apps erhalten:


Regler

  • Der Controller sollte nur eine Zwischenschicht zwischen Modell und Ansicht sein. Versuche es so dünn wie möglich zu machen .

  • Es wird dringend empfohlen, Geschäftslogik in der Steuerung zu vermeiden . Es sollte zum Modell verschoben werden.

  • Der Controller kann mit anderen Controllern über den Methodenaufruf (möglich, wenn Kinder mit dem Elternteil kommunizieren möchten) oder die Methoden $ emit , $ Broadcast und $ on kommunizieren . Die gesendeten und gesendeten Nachrichten sollten auf ein Minimum beschränkt werden.

  • Der Controller sollte sich nicht um Präsentation oder DOM-Manipulation kümmern .

  • Versuchen Sie , verschachtelte Controller zu vermeiden . In diesem Fall wird der übergeordnete Controller als Modell interpretiert. Injizieren Sie stattdessen Modelle als Shared Services.

  • Scope in der Steuerung sollte verwendet werden Bindungsmodell mit Blick und
    Einkapseln Ansicht Modell für Presentation Model Design - Muster.


Umfang

Behandeln Sie den Bereich in Vorlagen als schreibgeschützt und in Controllern als schreibgeschützt . Der Zweck des Bereichs besteht darin, sich auf das Modell zu beziehen, nicht auf das Modell.

Stellen Sie beim bidirektionalen Binden (ng-Modell) sicher, dass Sie nicht direkt an die Bereichseigenschaften binden.


Modell

Das Modell in AngularJS ist ein vom Dienst definierter Singleton .

Das Modell bietet eine hervorragende Möglichkeit, Daten und Anzeige zu trennen.

Modelle sind Hauptkandidaten für Unit-Tests, da sie normalerweise genau eine Abhängigkeit haben (irgendeine Form von Ereignisemitter, im allgemeinen Fall $ rootScope ) und eine hoch testbare Domänenlogik enthalten .

  • Das Modell sollte als Implementierung einer bestimmten Einheit betrachtet werden. Es basiert auf dem Prinzip der Einzelverantwortung. Unit ist eine Instanz, die für ihren eigenen Umfang verwandter Logik verantwortlich ist, die eine einzelne Entität in der realen Welt darstellen und in der Programmierwelt in Bezug auf Daten und Status beschreiben kann .

  • Das Modell sollte die Daten Ihrer Anwendung kapseln und eine API für den Zugriff auf und die Bearbeitung dieser Daten bereitstellen .

  • Das Modell sollte tragbar sein, damit es problemlos zu einer ähnlichen Anwendung transportiert werden kann.

  • Durch das Isolieren der Einheitenlogik in Ihrem Modell haben Sie das Auffinden, Aktualisieren und Warten vereinfacht.

  • Das Modell kann Methoden allgemeinerer globaler Modelle verwenden, die für die gesamte Anwendung gelten.

  • Versuchen Sie, die Zusammensetzung anderer Modelle in Ihrem Modell mithilfe der Abhängigkeitsinjektion zu vermeiden, wenn es nicht wirklich darauf ankommt, die Kopplung der Komponenten zu verringern und die Testbarkeit und Verwendbarkeit der Einheiten zu verbessern .

  • Vermeiden Sie die Verwendung von Ereignis-Listenern in Modellen. Dies erschwert das Testen und tötet Modelle im Allgemeinen nach dem Prinzip der Einzelverantwortung.

Modellimplementierung

Da das Modell eine gewisse Logik in Bezug auf Daten und Status enthalten sollte, sollte es den Zugriff auf seine Mitglieder architektonisch einschränken, damit wir eine lose Kopplung gewährleisten können.

In der AngularJS-Anwendung können Sie dies mithilfe des werkseitigen Servicetyps definieren . Auf diese Weise können wir private Eigenschaften und Methoden sehr einfach definieren und auch öffentlich zugängliche Eigenschaften an einem einzigen Ort zurückgeben, sodass sie für Entwickler wirklich lesbar sind.

Ein Beispiel :

angular.module('search')
.factory( 'searchModel', ['searchResource', function (searchResource) {

  var itemsPerPage = 10,
  currentPage = 1,
  totalPages = 0,
  allLoaded = false,
  searchQuery;

  function init(params) {
    itemsPerPage = params.itemsPerPage || itemsPerPage;
    searchQuery = params.substring || searchQuery;
  }

  function findItems(page, queryParams) {
    searchQuery = queryParams.substring || searchQuery;

    return searchResource.fetch(searchQuery, page, itemsPerPage).then( function (results) {
      totalPages = results.totalPages;
      currentPage = results.currentPage;
      allLoaded = totalPages <= currentPage;

      return results.list
    });
  }

  function findNext() {
    return findItems(currentPage + 1);
  }

  function isAllLoaded() {
    return allLoaded;
  }

  // return public model API  
  return {
    /**
     * @param {Object} params
     */
    init: init,

    /**
     * @param {Number} page
     * @param {Object} queryParams
     * @return {Object} promise
     */
    find: findItems,

    /**
     * @return {Boolean}
     */
    allLoaded: isAllLoaded,

    /**
     * @return {Object} promise
     */
    findNext: findNext
  };
});

Neue Instanzen erstellen

Vermeiden Sie es, über eine Factory zu verfügen, die eine neue Funktion zurückgibt, da dies die Abhängigkeitsinjektion beeinträchtigt und sich die Bibliothek insbesondere für Dritte unangenehm verhält.

Eine bessere Möglichkeit, dasselbe zu erreichen, besteht darin, die Factory als API zu verwenden, um eine Sammlung von Objekten mit den damit verbundenen Getter- und Setter-Methoden zurückzugeben.

angular.module('car')
 .factory( 'carModel', ['carResource', function (carResource) {

  function Car(data) {
    angular.extend(this, data);
  }

  Car.prototype = {
    save: function () {
      // TODO: strip irrelevant fields
      var carData = //...
      return carResource.save(carData);
    }
  };

  function getCarById ( id ) {
    return carResource.getById(id).then(function (data) {
      return new Car(data);
    });
  }

  // the public API
  return {
    // ...
    findById: getCarById
    // ...
  };
});

Globales Modell

Versuchen Sie im Allgemeinen, solche Situationen zu vermeiden und Ihre Modelle richtig zu gestalten, damit sie in die Steuerung eingespritzt und aus Ihrer Sicht verwendet werden können.

In einigen Fällen erfordern einige Methoden eine globale Zugänglichkeit innerhalb der Anwendung. Um dies zu ermöglichen, können Sie die Eigenschaft ' common ' in $ rootScope definieren und sie während des Bootstraps der Anwendung an commonModel binden :

angular.module('app', ['app.common'])
.config(...)
.run(['$rootScope', 'commonModel', function ($rootScope, commonModel) {
  $rootScope.common = 'commonModel';
}]);

Alle Ihre globalen Methoden befinden sich in einem " gemeinsamen " Eigentum. Dies ist eine Art Namespace .

Definieren Sie jedoch keine Methoden direkt in Ihrem $ rootScope . Dies kann zu unerwartetem Verhalten führen, wenn es mit der ngModel-Direktive in Ihrem Ansichtsbereich verwendet wird, was im Allgemeinen Ihren Bereich verschmutzt und dazu führt, dass Bereichsmethoden Probleme überschreiben.


Ressource

Mit Resource können Sie mit verschiedenen Datenquellen interagieren .

Sollte nach dem Prinzip der Einzelverantwortung umgesetzt werden .

Im besonderen Fall ist es wiederverwendbar Proxy für HTTP / JSON-Endpunkte.

Ressourcen werden in Modelle eingefügt und bieten die Möglichkeit, Daten zu senden / abzurufen.

Ressourcenimplementierung

Eine Factory, die ein Ressourcenobjekt erstellt, mit dem Sie mit serverseitigen RESTful-Datenquellen interagieren können.

Das zurückgegebene Ressourcenobjekt verfügt über Aktionsmethoden, die Verhalten auf hoher Ebene bereitstellen, ohne dass mit dem $ http-Dienst auf niedriger Ebene interagiert werden muss.


Dienstleistungen

Sowohl Modell als auch Ressource sind Dienste .

Dienste sind nicht zugeordnet, lose gekoppelt Funktionseinheiten, die in sich geschlossen sind.

Dienste sind eine Funktion, die Angular von der Serverseite aus für clientseitige Webanwendungen bereitstellt, wo Dienste seit langem häufig verwendet werden.

Dienste in Angular-Apps sind austauschbare Objekte, die mithilfe der Abhängigkeitsinjektion miteinander verbunden werden.

Angular bietet verschiedene Arten von Diensten. Jeder mit seinen eigenen Anwendungsfällen. Weitere Informationen finden Sie unter Grundlegendes zu Servicetypen.

Versuchen Sie, die Hauptprinzipien der Servicearchitektur in Ihrer Anwendung zu berücksichtigen .

Im Allgemeinen laut Web Services Glossar :

Ein Dienst ist eine abstrakte Ressource, die die Fähigkeit darstellt, Aufgaben auszuführen, die aus Sicht von Anbieterentitäten und anfordernden Entitäten eine kohärente Funktionalität bilden. Um verwendet zu werden, muss ein Service von einem konkreten Anbieteragenten realisiert werden.


Client-seitige Struktur

Im Allgemeinen wird die Client-Seite der Anwendung in Module aufgeteilt . Jedes Modul sollte als Einheit testbar sein.

Versuchen Sie, Module abhängig von Merkmal / Funktionalität oder Ansicht zu definieren , nicht nach Typ. Weitere Informationen finden Sie in der Präsentation von Misko .

Modulkomponenten können herkömmlicherweise nach Typen wie Steuerungen, Modellen, Ansichten, Filtern, Anweisungen usw. gruppiert werden.

Das Modul selbst bleibt jedoch wiederverwendbar , übertragbar und testbar .

Für Entwickler ist es auch viel einfacher, einige Teile des Codes und alle seine Abhängigkeiten zu finden.

Bitte beachten Sie - Code - Organisation in Groß AngularJS und JavaScript - Anwendungen für weitere Einzelheiten.

Ein Beispiel für die Strukturierung von Ordnern :

|-- 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

Ein gutes Beispiel für die Strukturierung von Winkelanwendungen ist die Angular-App - https://github.com/angular-app/angular-app/tree/master/client/src

Dies wird auch von modernen Anwendungsgeneratoren berücksichtigt - https://github.com/yeoman/generator-angular/issues/109


5
Ich habe ein Problem mit: "Es wird dringend empfohlen, Geschäftslogik in Controllern zu vermeiden. Sie sollte in das Modell verschoben werden." Aus der offiziellen Dokumentation können Sie jedoch lesen: "Im Allgemeinen sollte ein Controller nicht versuchen, zu viel zu tun. Er sollte nur die Geschäftslogik enthalten, die für eine einzelne Ansicht erforderlich ist." Sprechen wir über dasselbe?
Op1ekun

3
Ich würde sagen - Controller als Ansichtsmodell behandeln.
Artem Platonov

1
+1. Einige tolle Tipps hier! 2. Leider searchModelfolgt das Beispiel von nicht den Empfehlungen zur Wiederverwendbarkeit. Es wäre besser, die Konstanten über den constantDienst zu importieren . 3. Irgendeine Erklärung, was hier gemeint ist?:Try to avoid having a factory that returns a new able function
Dmitri Zaitsev

1
Auch das Überschreiben der Objekteigenschaft prototypebricht die Vererbung, stattdessen kann man verwendenCar.prototype.save = ...
Dmitri Zaitsev

2
@ChristianAichinger, hier geht es um die Art der JavaScript-Prototypkette, die Sie dazu zwingt, entweder einen objectin Ihrem bidirektionalen Bindungsausdruck zu verwenden, um sicherzustellen, dass Sie in die genaue Eigenschaft oder setterFunktion schreiben . Wenn Sie die direkte Eigenschaft Ihres Bereichs ( ohne Punkt ) verwenden, besteht das Risiko, dass Sie die gewünschte Zieleigenschaft mit der neu erstellten im nächstgelegenen oberen Bereich der Prototypenkette ausblenden, wenn Sie darauf schreiben. Dies wird besser in Miskos Präsentation erklärt
Artem Platonov

46

Ich glaube, dass Igor dies, wie aus dem von Ihnen bereitgestellten Zitat hervorgeht, nur die Eisbergspitze eines weitaus größeren Problems ist.

MVC und seine Derivate (MVP, PM, MVVM) sind alle gut und gut innerhalb eines einzelnen Agenten, aber eine Server-Client-Architektur ist für alle Zwecke ein System mit zwei Agenten, und die Leute sind oft so besessen von diesen Mustern, dass sie das vergessen Das vorliegende Problem ist weitaus komplexer. Wenn sie versuchen, diese Prinzipien einzuhalten, erhalten sie tatsächlich eine fehlerhafte Architektur.

Lass uns das Stück für Stück machen.

Die Richtlinien

Ansichten

Im Winkelkontext ist die Ansicht das DOM. Die Richtlinien sind:

Machen:

  • Aktuelle Bereichsvariable (schreibgeschützt).
  • Rufen Sie den Controller für Aktionen auf.

Nicht:

  • Setzen Sie eine Logik.

So verlockend, kurz und harmlos das aussieht:

ng-click="collapsed = !collapsed"

Es bedeutet für jeden Entwickler, dass er nun sowohl die Javascript-Dateien als auch die HTML-Dateien überprüfen muss, um zu verstehen, wie das System funktioniert.

Controller

Machen:

  • Binden Sie die Ansicht an das 'Modell', indem Sie Daten in den Bereich einfügen.
  • Reagieren Sie auf Benutzeraktionen.
  • Beschäftige dich mit Präsentationslogik.

Nicht:

  • Beschäftige dich mit jeder Geschäftslogik.

Der Grund für die letzte Richtlinie ist, dass Controller Controller von Ansichten sind, keine Entitäten. noch sind sie wiederverwendbar.

Man könnte argumentieren, dass Direktiven wiederverwendbar sind, aber auch Direktiven sind Schwestern der Ansichten (DOM) - sie sollten niemals Entitäten entsprechen.

Sicher, manchmal stellen Ansichten Entitäten dar, aber das ist ein ziemlich spezifischer Fall.

Mit anderen Worten, Controller sollten sich auf die Präsentation konzentrieren. Wenn Sie die Geschäftslogik einbringen, werden Sie wahrscheinlich nicht nur einen aufgeblasenen, wenig verwaltbaren Controller haben, sondern Sie verletzen auch das Prinzip der Trennung von Bedenken .

Daher sind Controller in Angular eher Präsentationsmodelle oder MVVM .

Und wenn Controller sich nicht mit Geschäftslogik befassen sollten, wer sollte das tun?

Was ist ein Modell?

Ihr Kundenmodell ist oft teilweise und veraltet

Sofern Sie keine Offline-Webanwendung oder eine schrecklich einfache Anwendung (wenige Entitäten) schreiben, ist es sehr wahrscheinlich, dass Ihr Client-Modell:

  • Teilweise
    • Entweder hat es nicht alle Entitäten (wie im Fall der Paginierung)
    • Oder es hat nicht alle Daten (wie im Fall der Paginierung)
  • Veraltet - Wenn das System mehr als einen Benutzer hat, können Sie zu keinem Zeitpunkt sicher sein, dass das vom Client gehaltene Modell mit dem des Servers übereinstimmt.

Das reale Modell muss bestehen bleiben

Im traditionellen MCV ist das Modell das einzige, was beibehalten wird . Wann immer wir über Modelle sprechen, müssen diese irgendwann beibehalten werden. Ihr Client kann Modelle nach Belieben bearbeiten, aber bis der Roundtrip zum Server erfolgreich abgeschlossen wurde, ist die Aufgabe noch nicht erledigt.

Folgen

Die beiden oben genannten Punkte sollten als Vorsicht dienen - das Modell, das Ihr Kunde besitzt, kann nur eine teilweise, meist einfache Geschäftslogik beinhalten.

Daher ist es im Client-Kontext möglicherweise ratsam , Kleinbuchstaben zu verwenden M- es handelt sich also wirklich um mVC , mVP und mVVm . Das große Mist für den Server.

Geschäftslogik

Vielleicht ist eines der wichtigsten Konzepte für Geschäftsmodelle, dass Sie sie in zwei Typen unterteilen können (ich lasse das dritte View-Business weg, da dies eine Geschichte für einen anderen Tag ist):

  • Domänenlogik - auch bekannt als Enterprise Business Rules , die Logik, die anwendungsunabhängig ist. Geben Sie beispielsweise ein Modell mit firstNameund sirNameEigenschaften an, ein Getter wie getFullName()kann als anwendungsunabhängig betrachtet werden.
  • Anwendungslogik - auch bekannt als Anwendungsgeschäftsregeln , die anwendungsspezifisch sind. Zum Beispiel Fehlerprüfungen und -behandlung.

Es ist wichtig zu betonen, dass beide innerhalb eines Kundenkontexts keine „echte“ Geschäftslogik sind - sie befassen sich nur mit dem Teil davon, der für den Kunden wichtig ist. Die Anwendungslogik (nicht die Domänenlogik) sollte dafür verantwortlich sein, die Kommunikation mit dem Server und die meisten Benutzerinteraktionen zu erleichtern. Die Domänenlogik ist weitgehend klein, entitätsspezifisch und präsentationsgesteuert.

Die Frage bleibt weiterhin: Wo werfen Sie sie in eine eckige Anwendung?

3 vs 4-Schicht-Architektur

Alle diese MVW-Frameworks verwenden drei Ebenen:

Drei Kreise.  Innenmodell, Mittelsteuerung, Außenansicht

Bei Kunden gibt es jedoch zwei grundlegende Probleme:

  • Das Modell ist teilweise, abgestanden und bleibt nicht bestehen.
  • Kein Platz für Anwendungslogik.

Eine Alternative zu dieser Strategie ist die 4-Schicht-Strategie :

4 Kreise von innen nach außen - Unternehmensgeschäftsregeln, Anwendungsgeschäftsregeln, Schnittstellenadapter, Frameworks und Treiber

Das eigentliche Problem hierbei ist die Schicht mit den Geschäftsregeln für Anwendungen (Anwendungsfälle), die bei Kunden häufig nicht funktioniert.

Diese Schicht wird von Interaktoren (Onkel Bob) realisiert, was Martin Fowler so ziemlich eine Operationsschicht-Service-Schicht nennt .

Konkretes Beispiel

Betrachten Sie die folgende Webanwendung:

  • Die Anwendung zeigt eine paginierte Liste von Benutzern.
  • Der Benutzer klickt auf "Benutzer hinzufügen".
  • Ein Modell wird mit einem Formular zum Ausfüllen von Benutzerdetails geöffnet.
  • Der Benutzer füllt das Formular aus und drückt auf Senden.

Ein paar Dinge sollten jetzt passieren:

  • Das Formular sollte vom Client validiert sein.
  • Eine Anfrage wird an den Server gesendet.
  • Ein Fehler ist zu behandeln, falls es einen gibt.
  • Die Benutzerliste muss möglicherweise (aufgrund von Paginierung) aktualisiert werden oder nicht.

Wo werfen wir das alles hin?

Wenn Ihre Architektur einen Controller umfasst, der aufruft $resource, geschieht dies alles innerhalb des Controllers. Aber es gibt eine bessere Strategie.

Eine vorgeschlagene Lösung

Das folgende Diagramm zeigt, wie das obige Problem durch Hinzufügen einer weiteren Anwendungslogikschicht in Angular-Clients gelöst werden kann:

4 Felder - DOM zeigt auf Controller, was auf Anwendungslogik zeigt, was auf $ resource zeigt

Also fügen wir $ resource eine Ebene zwischen Controller hinzu, diese Ebene (nennen wir es Interaktor ):

  • Ist ein Service . Im Falle von Benutzern kann es aufgerufen werden UserInteractor.
  • Es bietet Methoden entsprechend Fälle zu verwenden , Einkapseln Anwendungslogik .
  • Es steuert die an den Server gestellten Anforderungen. Anstelle eines Controllers, der $ resource mit Freiformparametern aufruft, stellt diese Schicht sicher, dass an den Server gesendete Anforderungen Daten zurückgeben, auf die die Domänenlogik einwirken kann.
  • Es schmückt die zurückgegebene Datenstruktur mit einem Domänenlogik- Prototyp.

Und so mit den Anforderungen des obigen konkreten Beispiels:

  • Der Benutzer klickt auf "Benutzer hinzufügen".
  • Der Controller fragt den Interaktor nach einem leeren Benutzermodell, das mit einer Geschäftslogikmethode wie dekoriert ist validate()
  • Bei der Übermittlung ruft der Controller die Modellmethode auf validate().
  • Wenn dies fehlschlägt, behandelt der Controller den Fehler.
  • Bei Erfolg ruft der Controller den Interaktor mit auf createUser()
  • Der Interaktor ruft $ resource auf
  • Nach der Antwort delegiert der Interaktor alle Fehler an den Controller, der sie behandelt.
  • Nach erfolgreicher Antwort stellt der Interaktor sicher, dass die Benutzerliste bei Bedarf aktualisiert wird.

AngularJS ist also MVW (wobei W für was auch immer steht), da ich wählen kann, ob ich einen Controller (mit der gesamten Geschäftslogik) oder ein Ansichtsmodell / Präsentator (ohne Geschäftslogik, aber nur einen Code zum Ausfüllen der Ansicht) mit BL in habe ein separater Service? Habe ich recht?
BAD_SEED

Beste Antwort. Haben Sie auf GitHub ein echtes Beispiel für eine 4-lagige Winkel-App?
RPallas

1
@RPallas, nein ich nicht (wünschte ich hätte Zeit dafür). Wir probieren derzeit eine Architektur aus, bei der die 'Anwendungslogik' nur ein Grenzinteraktor ist. ein Resolver zwischen ihm und dem Controller und ein Ansichtsmodell mit einer Ansichtslogik. Wir experimentieren immer noch, also nicht 100% der Vor- oder Nachteile. Aber wenn ich fertig bin, hoffe ich, irgendwo einen Blog zu schreiben.
Izhaki

1
@heringer Grundsätzlich haben wir Modelle eingeführt - OOP-Konstrukte, die Domänenentitäten darstellen. Es sind diese Modelle, die mit Ressourcen kommunizieren, nicht mit Controllern. Sie kapseln die Domänenlogik. Controller rufen Modelle auf, die wiederum Ressourcen aufrufen.
Izhaki

1
@ alex440 Nein. Obwohl es nun zwei Monate her ist, dass mir ein ernsthafter Blog-Beitrag zu diesem Thema zur Verfügung steht. Weihnachten kommt - möglicherweise dann.
Izhaki

5

Ein kleines Problem im Vergleich zu den großen Ratschlägen in Artems Antwort, aber in Bezug auf die Lesbarkeit des Codes fand ich es am besten, die API vollständig im returnObjekt zu definieren , um das Hin- und Hergehen im Code zu minimieren und zu prüfen, ob Variablen definiert sind:

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, ...) {
    ...
    }
  }
});

Wenn das returnObjekt "zu überfüllt" aussieht, ist dies ein Zeichen dafür, dass der Dienst zu viel tut.


0

AngularJS implementiert MVC nicht auf herkömmliche Weise, sondern implementiert etwas, das näher an MVVM (Model-View-ViewModel) liegt. ViewModel kann auch als Binder bezeichnet werden (im Winkelfall kann es $ scope sein). Das Modell -> Wie wir wissen, kann das Modell im Winkel einfach nur alte JS-Objekte oder die Daten in unserer Anwendung sein

Die Ansicht -> die Ansicht in angleJS ist der HTML-Code, der von angleJS durch Anwenden der Anweisungen oder Anweisungen oder Bindungen analysiert und kompiliert wurde. Der Hauptpunkt hier ist in angle, dass die Eingabe nicht nur die einfache HTML-Zeichenfolge (innerHTML) ist, sondern es ist ein vom Browser erstelltes DOM.

Das ViewModel -> ViewModel ist tatsächlich der Binder / die Brücke zwischen Ihrer Ansicht und dem Modell, wenn es sich um $ scope handelt, um den von uns verwendeten $ scope zu initialisieren und zu erweitern.

Wenn ich die Antwort zusammenfassen möchte: In der angleJS-Anwendung verweist $ scope auf die Daten, Controller steuert das Verhalten und View verwaltet das Layout, indem es mit dem Controller interagiert, um sich entsprechend zu verhalten.


-1

Um die Frage klar zu formulieren, verwendet Angular verschiedene Entwurfsmuster, die wir bereits in unserer regulären Programmierung angetroffen haben. 1) Wenn wir unsere Steuerungen oder Anweisungen, Fabriken, Dienste usw. in Bezug auf unser Modul registrieren. Hier versteckt es die Daten vor dem globalen Raum. Welches ist Modulmuster . 2) Wenn Angular seine Dirty-Prüfung zum Vergleichen der Bereichsvariablen verwendet, wird hier das Beobachtermuster verwendet . 3) Alle übergeordneten untergeordneten Bereiche in unseren Controllern verwenden das prototypische Muster. 4) Beim Injizieren der Dienste wird das Factory-Muster verwendet .

Insgesamt werden verschiedene bekannte Entwurfsmuster verwendet, um die Probleme zu lösen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.