So vermeiden Sie… Helfer- oder… Manager-Klassen

9

Ich habe einige Helferklassen in meinem Projekt. Ich habe gelesen, dass dies eine schlechte Sache ist, aber ich vermute, dass "Helper" das falsche Suffix für sie ist. Ich werde ein Beispiel geben.

Erstens habe ich eine UserKlasse. Ich brauche eine Methode GetSuggestedFriends()für einen Benutzer. Ich möchte die Logik zum Bestimmen der Liste der vorgeschlagenen Freunde aus der UserKlasse heraushalten , damit sie nicht aufgebläht wird. Im Moment habe ich eine, FriendshipHelperdie eine Userin ihrem Konstruktor erhält . Es enthält die Logik, um vorgeschlagene Freunde zu finden, und ich kann jetzt anrufen myUser.FriendshipHelper.GetSuggestedFriends().

Ursprünglich gab es FriendshipHelpernur statische Methoden, und Userin jedes wurde ein Objekt übergeben. Wenn ich die Klasse jetzt von Grund auf neu schreiben würde, würde ich sie vielleicht nennen FriendshipManager- sie macht auch Dinge wie das Hinzufügen und Entfernen von Freunden.

Ich habe auch gelesen, dass der ...ManagerUnterricht schlecht ist. Wie soll ich diese Klasse nennen? Oder ist das "schlechter Code"? Wo sollte die Logik zum Abrufen vorgeschlagener Freunde, aktueller Freunde und zum Hinzufügen und Entfernen von Freunden live sein? Sicher nicht alle in einer Riesenklasse User?

user1002973
quelle
Wo lebt dieser Code? Ist es ein Service? Greift es auf einen Datenspeicher zu? Es ist die Benutzeroberfläche für diese freundlichen Sachen?
Telastyn
3
Sobald Sie alle statischen Methoden losgeworden sind und ein echtes Zuhause in Ihrem OOP-Design gefunden haben, sind diese Klassen wirklich keine Hilfsklassen mehr. Sie können sie also umbenennen. An einem FriendshipManager ist nichts auszusetzen, wenn Sie Freundschaften in Ihrem Projekt verwalten müssen.
JeffO
Was ist los mit Facebook?
toniedzwiedz

Antworten:

10

So vermeiden Sie… Helfer- oder… Manager-Klassen «

Im Allgemeinen: durch gutes Design

Erstens habe ich eine Benutzerklasse. Ich benötige eine Methode GetSuggestedFriends () für einen Benutzer.

Ja. A user hat eine Beziehung zu anderen users. Und die Beziehung könnte als Methode ausgedrückt werden user, z user.isFriend(user2). Dies liegt in der Verantwortung des userObjekts. Außerdem bitten Sie ein anderes Objekt um Hilfe bei der Suche nach anderen Freunden . Sie delegieren die Verantwortung für das Finden von Freunden an ein anderes Objekt, und das ist in Ordnung .

Im Moment habe ich einen FriendshipHelper, der einen Benutzer in seinem Konstruktor empfängt. Es enthält die Logik zum Abrufen vorgeschlagener Freunde, und ich kann jetzt myUser.FriendshipHelper.GetSuggestedFriends () aufrufen.

Das ist nicht per se schlecht, hat aber einen Nachteil: den „Helper“ mit einer Initialisierung userGrenzen der Möglichkeiten zu , dass man user.

Was Sie brauchen, ist ein Objekt , mit dem Sie jedem Benutzer Freunde finden können . So eine generische Methode würde Sinn machen: userMatcher.findFriendsFor(user)die Rückkehr eine liefert Sammlung von möglichen Freunden ( user).

Wenn ich die Klasse jetzt von Grund auf neu schreiben würde, würde ich sie vielleicht FriendshipManager nennen

Ihr Problem besteht nicht darin, "Hilfsklassen" zu schreiben, sondern die richtigen Namen zu finden . ;)

Es macht auch Dinge wie das Hinzufügen und Entfernen von Freunden.

Das ist ein falsches Design . Nehmen Sie sich zum Beispiel: Fügt Ihre Mutter Ihrem Leben Freunde hinzu oder fügen Sie sie selbst hinzu?

Natürlich ist die Sammlung von Freunden eine Eigenschaft von sich userselbst, ebenso wie die Methode user.addFriend(user)oderuser.removeFriend(user)

Wie soll ich diese Klasse nennen?

Wie gesagt: Sie haben nur ein Namensproblem und Ihre "Helfer" sind in Ordnung . Sie müssen jedoch genauer über die Verantwortlichkeiten der einzelnen Objekte nachdenken .

Wo sollte die Logik zum Abrufen vorgeschlagener Freunde, aktueller Freunde und zum Hinzufügen und Entfernen von Freunden live sein? Sicherlich nicht alle in einer riesigen Benutzerklasse

Nein. Dies sind zwei Jobs, für die Sie ein separates Objekt benötigen , wie im wirklichen Leben, wo Sie Menschen und eine Partnervermittlung haben .

Thomas Junk
quelle
3
Tolle Erklärung, aber du hast meine Mutter eindeutig nie getroffen. : '(
Matt
1
@ HEATH3N Ich hoffe, das hat keinen Einfluss auf Ihre Softwaremodellierungsfähigkeiten.
Thomas Junk
3

Ich würde vorschlagen, dass Sie eine FriendshipServiceKlasse haben, die eine (nicht statische) GetSuggestedFriends(User)Methode hat. Vermeiden Sie statische Methoden, da Sie keine Schnittstelle implementieren können, die das Testen erschwert. Vermeiden Sie das Hinzufügen des Benutzerobjekts zum Konstruktor, da Sie Ihren FriendshipService möglicherweise um Methoden erweitern möchten, die sich nicht speziell auf einen einzelnen Benutzer beziehen. (Zum Beispiel möchten Sie möglicherweise einer Gruppe von Benutzern Freunde vorschlagen oder Freunde vorschlagen, die auf etwas anderem basieren.)

Ein Benutzer sollte sich des FriendshipService(aufgrund des Einzelverantwortungsmusters) höchstwahrscheinlich nicht bewusst sein.

Björn
quelle
7
Das Ändern des Suffixes von "Helper" in "Service" macht es nicht einfacher, sich anhand des Namens ein Bild von der Verantwortung der Klasse zu machen, was meiner Meinung nach das Herzstück der Frage ist.
Mike Partridge
Nun, der Name selbst sagt vielleicht nicht so viel aus, aber ich würde sagen, dass die Verwendung des Suffixes "Service" eine standardisiertere Art der Kommunikation ist, dass die Klasse eine Art fortgeschrittene Logik ausführt. "Helfer" -Klassen beziehen sich (zumindest nach meiner Erfahrung) normalerweise eher auf sehr einfache Aufgaben wie einfache Formatierung und kleine statische Methoden. Ich würde erwarten, dass Sie eine "Service" -Schnittstelle durch verschiedene Implementierungen ersetzen könnten. Darüber hinaus gibt es hier viele Fragen, nicht nur die Benennung.
Björn
Einverstanden. Alle drei von "Helper", "Manager" und "Service" sind Methoden, mit denen wir Methoden gruppieren, um Tonnen von superspezifischen Klassen mit einer einzigen Methode zu vermeiden, aber "Service" hat, wie Sie beschrieben haben, eine etwas größere Bedeutung. Ich würde hinzufügen, dass dies impliziert, dass die Klasse Teil der Service-Layer-Schnittstelle ist, was dazu beiträgt, den Zugriff auf die Geschäftslogik (die aus vielen spezifischeren Klassen bestehen kann) für eine bestimmte Domänenklasse zu vereinfachen. Ob sich die Vorschlagslogik in einer von der Add / Remove-Logik getrennten Klasse befinden sollte, hängt davon ab, wie komplex die Implementierung der Vorschlagslogik ist.
Mike Partridge
Wenn wir Klassen ThingManager oder ThingService benennen, öffnen wir die Tür zum Erstellen von Klassen, die außer Kontrolle geraten. Da der Name nichts Bestimmtes angibt, das zur Klasse gehört, schließt er auch nichts aus. Ich brauche eine neue Methode, die sich mit Dingen befasst. Wohin geht es? Idk, setzen Sie es mit allen anderen Methoden in ThingManager.
Scott Hannen