Ich verwende das MVC-Muster in meiner mit PHP erstellten Webanwendung.
Ich habe immer Probleme zu bestimmen, ob ich einen neuen dedizierten Controller für eine Reihe von Aktionen benötige oder ob ich sie in einem bereits vorhandenen Controller platzieren sollte.
Gibt es gute Faustregeln beim Erstellen von Controllern?
Zum Beispiel kann ich haben:
AuthenticationController
mit Aktionen:
index()
um das Anmeldeformular anzuzeigen.submit()
Formularübermittlung zu behandeln.logout()
, selbsterklärend.
ODER
LoginController
mit Aktionen:
index()
um das Anmeldeformular anzuzeigen.submit()
Formularübermittlung zu behandeln.
LogoutController
mit Aktion:
index()
um sich abzumelden.
ODER
AccountController
mit Aktionen:
loginGet()
um das Anmeldeformular anzuzeigen.loginPost()
um die Übermittlung des Anmeldeformulars zu handhaben.logoutGet()
um sich abzumelden.registerGet()
um das Anmeldeformular anzuzeigen.registerPost()
Formularübermittlung zu behandeln.Und alle anderen Aktionen, die mit einem Konto verbunden sind.
Antworten:
Denken Sie an die Tests , um die richtige Gruppierung für Controller zu finden .
(Selbst wenn Sie keine Tests durchführen, erhalten Sie einige sehr gute Einblicke in die Strukturierung Ihrer Controller, wenn Sie darüber nachdenken, wie Sie Ihre Controller testen würden.)
An kann
AuthenticationController
nicht selbst getestet werden, da es nur Funktionen zum An- und Abmelden enthält. Ihr Testcode muss jedoch zu Testzwecken gefälschte Konten erstellen, bevor eine erfolgreiche Anmeldung getestet werden kann. Sie könnten das zu testende Subsystem umgehen und direkt zu Ihrem Modell gehen, um die Testkonten zu erstellen. Dann haben Sie jedoch einen fragilen Test in der Hand: Wenn sich das Modell ändert, müssen Sie nicht nur den Code ändern, der testet das Modell, aber auch Code, der den Controller testet, obwohl die Schnittstelle und das Verhalten des Controllers unverändert geblieben sind. Das ist unvernünftig.A
LoginController
ist aus den gleichen Gründen ungeeignet: Sie können es nicht testen, ohne zuerst Konten zu erstellen, und es gibt noch weitere Dinge, die Sie nicht testen können, z. B. das Verhindern doppelter Anmeldungen, aber das Anmelden eines Benutzers nach dem Abmelden. (Da dieser Controller keine Abmeldefunktion hat.)An
AccountController
gibt Ihnen alles, was Sie für Ihre Tests benötigen: Sie können ein Testkonto erstellen und dann versuchen, sich anzumelden. Sie können das Konto löschen und dann sicherstellen, dass Sie sich nicht mehr anmelden können. Sie können das Passwort ändern und sicherstellen, dass das Für die Anmeldung usw. muss das richtige Passwort verwendet werden.Fazit: Um auch die kleinste Testsuite zu schreiben, müssen Sie alle Funktionen der
AccountController
verfügbaren Suite zur Verfügung stellen. Die Unterteilung in kleinere Steuerungen scheint zu behinderten Steuerungen mit unzureichender Funktionalität für einen ordnungsgemäßen Test zu führen. Dies ist ein sehr guter Hinweis darauf, dass die Funktionalität vonAccountController
die kleinste sinnvolle Unterteilung ist.Und im Allgemeinen funktioniert der Ansatz "Denken Sie an das Testen" nicht nur in diesem speziellen Szenario, sondern in jedem ähnlichen Szenario, auf das Sie in Zukunft stoßen.
quelle
Die Antwort ist nicht so offensichtlich
Bitte lassen Sie mich einige Dinge klären, bevor ich antwortende Aussagen mache. Zuerst:
Was ist der Controller?
Der Controller ist ein Teil des Systems, der die Anforderung steuert - nach dem Versand. Wir können es also als eine Reihe von Aktionen definieren, die sich auf ... was beziehen?
Was ist der Umfang der Steuerung?
Und das ist mehr oder weniger Teil, wenn wir eine Antwort haben werden. Was denken Sie? Ist es ein Controller von Dingen (zum Beispiel ein Konto) oder ein Controller von Aktionen? Natürlich ist es ein Controller eines Modells oder einer abstrakteren Sache, die Aktionen darauf bereitstellt.
Die Antwort ist...
Nein, Authentifizierung ist ein Prozess. Geh nicht so.
Hier gilt das gleiche. Login - Aktion. Erstellen Sie besser keinen Action-Controller (Sie haben kein korreliertes Modell damit).
Ziemlich gut, aber ich bin nicht davon überzeugt, dass es sich lohnt, diesen Low-Level-Controller (Controller ist Abstraktion selbst) zu bauen. Wie auch immer, das Erstellen von Methoden mit * Get oder * Post ist unklar.
Irgendein Vorschlag?
Ja, bedenken Sie es:
AccountController:
Und verwandtes Modell dazu, ofc Account-Klasse. Sie haben die Möglichkeit, Ihr Modell-Controller-Paar an einen anderen Ort zu verschieben (falls erforderlich) und einen klaren Code zu erstellen (es ist offensichtlich, was die
login()
Methode bedeutet). Das Modellieren ist besonders bei CRUD-Anwendungen sehr beliebt, und vielleicht ist es ein Weg für Sie.quelle
Controller werden normalerweise für eine bestimmte Ressource (eine Entitätsklasse, eine Tabelle in der Datenbank) erstellt, können aber auch erstellt werden, um Aktionen zu gruppieren, die für einen bestimmten Teil der Anwendung verantwortlich sind. In Ihren Beispielen wäre dies ein Controller, der die Sicherheit für die Anwendung übernimmt:
Hinweis : Legen Sie die sicherheitsrelevanten Aktionen und die Benutzerprofilaktionen nicht in demselben Controller ab. Dies ist möglicherweise sinnvoll, da sie sich auf den Benutzer beziehen. Einer sollte jedoch die Authentifizierung und der andere die Aktualisierung von E-Mails, Namen usw. übernehmen.
Mit Controllern, die für Ressourcen erstellt wurden (sagen wir
Task
), hätten Sie die üblichen CRUD- Aktionen:Natürlich haben Sie die Möglichkeit, dem gleichen Controller verwandte Ressourcen hinzuzufügen. Angenommen, Sie haben die Entität
Business
und jede hat mehrereBusinessService
Entitäten. Ein Controller dafür könnte folgendermaßen aussehen:Dieser Ansatz ist sinnvoll, wenn die zugehörigen untergeordneten Entitäten ohne die übergeordnete Entität nicht existieren können.
Dies sind meine Empfehlungen:
Subscription
Entität haben, deren Verfügbarkeit auf einer begrenzten Anzahl von Einträgen basiert, können Sie dem genannten Controller eine neue Aktion hinzufügenuse()
, die den einzigen Zweck hat, einen Eintrag von der zu subtrahierenSubscription
).Einige Ressourcen zur weiteren Lektüre hier .
quelle
Ich sehe zwei antagonistische Design- "Kräfte" (die nicht nur für Controller gelten):
Unter dem Gesichtspunkt der Kohäsivität hängen alle drei Aktionen (Anmelden, Abmelden, Registrierung) zusammen, aber Anmelden und Abmelden sind viel mehr als Registrierung. Sie sind semantisch miteinander verbunden (eines ist eine Inversion des anderen) und verwenden möglicherweise auch dieselben Serviceobjekte (ihre Implementierungen sind ebenfalls zusammenhängend).
Mein erster Instinkt wäre, die Anmeldung und Abmeldung in einem Controller zu gruppieren. Aber wenn die Implementierungen von Login & Logout-Controllern nicht so einfach sind (z. B. Login hat Captcha, mehr Authentifizierungsmethoden usw.), hätte ich kein Problem, sie zur Vereinfachung in LoginController und LogoutController zu unterteilen. Wo diese Schwelle der Komplexität liegt (wann Sie mit der Aufteilung des Controllers beginnen sollten), ist ein bisschen persönlich.
Denken Sie auch daran, dass Sie Ihren Code, was auch immer Sie anfangs entwerfen, bei Änderungen ändern können (und sollten). In diesem Fall ist es recht typisch, mit einem einfachen Design zu beginnen (einen AuthenticationController zu haben), und mit der Zeit erhalten Sie weitere Anforderungen, die den Code komplizieren. Sobald der Komplexitätsschwellenwert überschritten ist, sollten Sie ihn auf zwei Controller umgestalten.
Übrigens schlägt Ihr Code vor, dass Sie Benutzer mit GET-Anforderung abmelden. Das ist eine schlechte Idee, da HTTP GET nullipotent sein sollte (es sollte den Status der Anwendung nicht ändern).
quelle
Hier einige Faustregeln:
Organisieren Sie nach Thema oder Thema, wobei der Controller-Name der Name des Themas ist.
Denken Sie daran, dass der Name des Controllers in der URL angezeigt wird, die für Ihre Benutzer sichtbar ist. Daher sollte dies für sie vorzugsweise sinnvoll sein.
In der von Ihnen erwähnten Situation (Authentifizierung) hat das MVC-Team den Controller bereits für Sie geschrieben. Öffnen Sie Visual Studio 2013 und klicken Sie dann auf
AccountController.cs enthält alle Methoden zum Verwalten von Benutzerkonten:
Sie haben also nach Thema "Benutzerkonten und Authentifizierung" mit dem sichtbaren Themennamen "Konto" organisiert.
quelle
Terminologie
Ich glaube, es ist ein großes Missverständnis, eine Klasse, die einige HTTP-bezogene Methoden enthält, als "Controller" zu bezeichnen.
Controller ist eine Methode, die Anforderungen verarbeitet, jedoch keine Klasse, die solche Methoden enthält . Also
index()
,submit()
,logout()
sind Controller.Eine Klasse, die diese Art von Methoden enthält, wird als "Controller" bezeichnet, nur weil sie eine Gruppe von Controllern darstellt und eine Rolle als "unterster" Namespace spielt. In der FP-Sprache (wie Haskell) wäre es nur ein Modul. Es wird empfohlen, diese "Controller" -Klassen in OOP-Sprachen so zustandslos wie möglich zu halten, mit Ausnahme von Verweisen auf Dienste und andere programmweite Inhalte.
Die Antwort
Wenn die Terminologie aussortiert ist, lautet die Frage: "Wie sollen wir Controller in Namespaces / Module unterteilen?" Ich denke, die Antwort lautet: Controller in einem einzelnen Namespace / Modul sollten mit der gleichen Art von Daten umgehen . Zum Beispiel
UserController
beschäftigt sich in erster Linie mit Instanzen derUser
Klasse, aber gelegentlich berührt andere ähnliche Dinge, falls erforderlich.Da
login
,logout
und andere solche Aktionen sind meist mit der Sitzung zu tun, ist es wahrscheinlich am besten, legt sie im InnernSessionController
undindex
Controller, der nur ein Formular druckt, soll in platziert werdenLoginPageController
, da es offensichtlich mit Login - Seite beschäftigt. Es ist ein wenig sinnvoll, HTML-Rendering und Sitzungsverwaltung in einer einzigen Klasse zusammenzufassen. Dies würde gegen SRP und wahrscheinlich gegen eine Reihe anderer bewährter Methoden verstoßen .Allgemeines Prinzip
Wenn Sie Probleme bei der Entscheidung haben, wo ein Code abgelegt werden soll, beginnen Sie mit den Daten (und Typen), mit denen Sie sich befassen.
quelle