Verwenden Sie eine Service-Schicht mit MVC


12

Wenn ein Controller zu fett wird und sich die Modellinstanziierung summiert, kann eine Serviceschicht verwendet werden.

  • Wenn ich die Logik nur in eine Serviceklasse einbinde, erhalte ich eine Reihe von Services mit einer / zwei Methoden. Das fühlt sich an wie ein Code-Geruch. Irgendwelche Best Practices dazu?

  • Kann ein Dienst Modelle instanziieren?

  • Wenn ein Dienst Modelle instanziiert, können die Dienste nicht auf Einheiten getestet werden. Sie können nur durch Integrationstests abgedeckt werden?

Antworten:


23

In 'SOLID' steht das 'I' für Interface Segregation. Die ganze Idee dieses Prinzips besteht darin, große Schnittstellen in kleinere, modularere Schnittstellen aufzuteilen. Im MVC-Dienst würde normalerweise eine Schnittstelle vorhanden sein, auf die sich der Controller verlassen würde. Sie möchten nicht, dass Ihre Controller über die konkrete Implementierung dieses Dienstes informiert werden. Daher ist eine Reihe von Diensten mit einer oder zwei Methoden eine gute Sache.

Dienste geben normalerweise DTOs in großen Anwendungen oder Domänenmodelle direkt in kleineren Anwendungen zurück. DTOs bedeuten normalerweise mehr Arbeit, aber eine bessere Trennung der Bedenken. Der typische Fluss ist:

  • Controller ruft den Dienst an
  • Der Dienst gibt ein Objekt zurück (sei es ein DTO, ein Domänenmodell oder etwas anderes).
  • Der Controller ordnet das DTO / Domänenmodell einem Ansichtsmodell zu

Das Mapping kann manuell erfolgen, aber die meisten Entwickler bevorzugen das Auto-Mapping-Framework wie Automapper, da wir keinen Installationscode schreiben und ziemlich faul sein können :-)

http://en.wikipedia.org/wiki/Interface_segregation_principle

https://github.com/AutoMapper/AutoMapper

Eine von vielen Diskussionen zum Stackoverflow bezüglich der Verwendung von DTOs und Domänenmodellen: /programming/2680071/dto-or-domain-model-object-in-the-view-layer


1
Ich würde vorsichtig sein, einen Auto-Mapper hier zu verwenden hässlichbugger.org
Daniel Little

AutoMapper verfügt über eine integrierte Unit-Test-Funktion, mit der Sie alle Ihre Mapping-Routinen mit einer Zeile überprüfen können. Der Autor dieses Beitrags hat das nicht erwähnt.
CodeART

Aber er weiß davon und hat es benutzt. Die Kommentare gehen etwas darauf ein.
Daniel Little

2
Viele Klassen mit nur einer oder zwei Methoden bedeuten normalerweise, dass sie nicht zusammenhängend sind. Eine Serviceschicht sollte, falls vorhanden, dünn sein, wobei sich der Großteil der Logik in den Modellen befindet. Es erscheint ziemlich sinnlos, einen Blick an ein dummes Objekt zu binden, das nichts weiter als eine Eigentumstasche ist. Das Modell in MVC sollte das Rich-Domain-Modell sein, kein anämisches. Martinfowler.com/bliki/AnemicDomainModel.html
Andy

3

Controller sollten nur Aufrufe an das Modell enthalten (wo die Geschäftslogik stattfindet) und basierend auf diesen Aufrufen Daten für die Ansicht zuweisen (Informationsobjekte oder Fehlermeldungen), daher sind Controller selbst für eine sehr komplexe Seite recht klein, wenn der Controller noch vorhanden ist wird sehr groß Sie sollten denken, dass diese Seite vielleicht auf mehr Seiten erweitert werden sollte.

Trotzdem kann das Modell ziemlich groß sein ... Die Lösung, die ich gefunden habe, bestand darin, eine Variable im Controller zu haben, die angibt, welches Modell geladen werden soll, und für bestimmte Aufgaben lade ich das bestimmte Modell.

Versuchen Sie, das Modell-Ansicht-Controller-Modell wie folgt sauber zu befolgen:

  • Ansicht: Zeigt Daten an
  • Controller: Sammelt Benutzereingaben, fragt das Modell nach den angeforderten Daten und sendet sie an die Ansicht zurück
  • Modell: Interagiert mit der Datenbank und führt logische Aktionen aus, um Informationen vorzubereiten

2

In MVC ist das Modell nicht nur ein DTO oder eine Gruppe von Managern / Diensten, sondern soll die Konzepte darstellen, die Ihre Anwendung modelliert. Sie können sich dies als die gesamte Domäne oder die Geschäftslogik einschließlich Status und Verhalten vorstellen. Nun wissen wir, dass der Zweck des Controllers etwas klarer wird. Es ist einfach Aufgabe, Befehle in das Modell und das Ergebnis zurück in die Ansichten zu übersetzen. Dies erfolgt normalerweise in Form von ViewModels, die unterschiedlich sind, aber häufig mit dem Modell in MVC verwechselt werden.

Wenn Sie kein genau definiertes Modell haben, sind Sie möglicherweise an einem Punkt angelangt, an dem sich der größte Teil dieser Logik jetzt in den Controllern selbst befindet. An diesem Punkt können Sie diese Logik wieder in Manager- oder Serviceobjekte zurückziehen, um die Größe Ihrer Controller zu verringern. Diese Dienste kehren normalerweise zurück und arbeiten mit DTO / Entity-ähnlichen Objekten. Dann wird der Controller zur Zuordnungsschicht zwischen diesen Diensten und den Ansichtsmodellen. Ein paar gute Tipps zum Mapping finden Sie in diesem Artikel. Freunde lassen Freunde AutoMapper nicht verwenden .

Was Ihre Fragen betrifft, hängt die erste stark von Ihren Anwendungen ab. Sie müssen auf dem Weg ein Refactoring durchführen, das deutlicher werden sollte, sobald Sie die Logik von Ihren Controllern entfernt haben. Was das Testen betrifft, gibt es kein Problem, Modelle innerhalb von Diensten zu instanziieren. Wenn Sie jedoch Schwierigkeiten beim Testen haben, ist dies wahrscheinlich nur ein Zeichen dafür, dass Sie den Dienst in kleinere Teile mit jeweils einer Verantwortung aufteilen müssen.


-1

Ich finde Dienste sehr hilfreich, um Logik auszuführen, die möglicherweise von mehr als einem Controller ausgeführt werden muss oder die nicht spezifisch genug ist, um Teil des Controllers zu sein, abgesehen von der Tatsache, dass meine Controller dadurch nicht zu groß und schwer lesbar werden. .

Ich persönlich bin nicht einverstanden mit 'aaa', wenn er sagt, dass "Modell (wo die Geschäftslogik passiert)", da dies der ganze Grund ist, warum Sie Controller haben. Meiner Meinung nach müssen Modelle einfache Datenabstraktoren sein, damit Controller die erforderliche Aufgabe ausführen können. Auch hier sollten Dienste nicht in die Datenabstraktionsaufgabe einbezogen werden ...

sag nur yo ....


1
Wenn Ihr Modell nur ein dto ist, sind Sie in das anämische Domänenmodell antipattern martinfowler.com/bliki/AnemicDomainModel.html
Andy
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.