Laut Robert C. Martin heißt es in der SRP:
Es sollte nie mehr als einen Grund geben, warum sich eine Klasse ändert.
In seinem Buch Clean Code , Kapitel 3: Functions, zeigt er jedoch den folgenden Codeblock:
public Money calculatePay(Employee e) throws InvalidEmployeeType {
switch (e.type) {
case COMMISSIONED:
return calculateCommissionedPay(e);
case HOURLY:
return calculateHourlyPay(e);
case SALARIED:
return calculateSalariedPay(e);
default:
throw new InvalidEmployeeType(e.type);
}
}
Und dann heißt es:
Es gibt verschiedene Probleme mit dieser Funktion. Erstens ist es groß, und wenn neue Mitarbeitertypen hinzugefügt werden, wird es wachsen. Zweitens macht es ganz klar mehr als eine Sache. Drittens verstößt es gegen das Einzelverantwortungsprinzip (Single Responsibility Principle, SRP), weil es mehr als einen Grund für eine Änderung gibt . [Hervorhebung von mir]
Erstens dachte ich, dass die SRP für Klassen definiert wurde, aber es stellt sich heraus, dass sie auch für Funktionen gilt. Zweitens, wie kommt es, dass diese Funktion mehr als einen Grund hat, sich zu ändern ? Ich kann nur sehen, dass es sich aufgrund eines Mitarbeiterwechsels ändert.
Antworten:
Ein häufig übersehenes Detail des Grundsatzes der einheitlichen Verantwortung ist, dass die "Gründe für Änderungen" nach Anwendungsfallakteuren gruppiert sind (eine vollständige Erklärung finden Sie hier ).
In Ihrem Beispiel muss die
calculatePay
Methode geändert werden, wenn neue Arten von Mitarbeitern erforderlich sind. Da ein Mitarbeitertyp möglicherweise nichts mit einem anderen zu tun hat, wäre es ein Verstoß gegen das Prinzip, wenn Sie ihn zusammenhalten, da sich die Änderung auf verschiedene Benutzergruppen (oder Anwendungsfallakteure) im System auswirken würde.Nun zur Frage, ob das Prinzip für Funktionen gilt: Auch wenn Sie in nur einer Methode eine Verletzung haben, ändern Sie eine Klasse aus mehr als einem Grund, es handelt sich also immer noch um eine Verletzung von SRP.
quelle
Auf Seite 176, Kapitel 12: Entstehung, enthält das Buch im Abschnitt mit dem Titel Minimale Klassen und Methoden eine Art Korrektur, indem Folgendes angegeben wird:
und
Offensichtlich spricht er von Dogmatismus, wenn er der SRP folgt, um ganz feine, unschuldige Methoden wie
calculatePay()
oben zu brechen .quelle
Wenn Herr Martin die SRP auf eine Funktion anwendet, erweitert er implizit seine Definition der SRP. Da die SRP eine OO-spezifische Formulierung eines allgemeinen Prinzips ist und eine gute Idee ist, wenn sie auf Funktionen angewendet wird, sehe ich darin kein Problem Definition).
Ich sehe auch nicht mehr als einen Grund für eine Änderung, und ich glaube nicht, dass es hilfreich ist, die SRP in Bezug auf "Verantwortlichkeiten" oder "Gründe für eine Änderung" zu betrachten. Im Grunde geht es der SRP darum, dass Software-Entitäten (Funktionen, Klassen usw.) eines tun und es gut machen sollten.
Wenn Sie sich meine Definition ansehen, ist sie nicht weniger vage als der übliche Wortlaut der SRP. Das Problem mit den üblichen Definitionen der SRP ist nicht, dass sie zu vage sind, sondern dass sie versuchen, etwas zu genau zu sagen, das im Wesentlichen vage ist.
Wenn Sie sich ansehen, was
calculatePay
passiert, dann handelt es sich eindeutig um eine einzige Sache: Versand nach Typ. Da Java über integrierte Methoden für typbasiertes Versenden verfügt,calculatePay
ist es unelegant und nicht idiomatisch. Daher sollte es umgeschrieben werden, jedoch nicht aus den angegebenen Gründen.quelle
Du hast recht @Enrique. Unabhängig davon, ob es sich um eine Funktion oder eine Methode einer Klasse handelt, bedeutet die SRP, dass Sie in diesem Codeblock nur eines tun.
Die "Grund zu ändern" -Anweisung ist manchmal etwas irreführend, aber wenn Sie ändern
calculateSalariedPay
odercalculateHourlyPay
oder die Aufzählung vonEmployee.type
Sie müssen diese Methode ändern.In Ihrem Beispiel die Funktion:
Meiner Meinung nach handelt es sich nicht direkt um eine SRP-Verletzung, da die Switch-Cases und die Calls nicht kürzer geschrieben werden können, wenn man an Employee denkt und die Methoden bereits existieren. Auf jeden Fall handelt es sich um einen eindeutigen Verstoß gegen das Open-Closed-Prinzip (OCP), da Sie beim Hinzufügen von Mitarbeitertypen "case" -Statements anhängen müssen. Es handelt sich also um eine schlechte Implementierung: Refactor.
Wir wissen nicht, wie das 'Geld' berechnet werden soll, aber der einfachste Weg ist, eine
Employee
Schnittstelle und einige konkrete Implementierungen mitgetMoney
Methoden zu haben. In diesem Fall ist die gesamte Funktion überflüssig.Wenn es komplizierter ist, es zu berechnen, könnte man das Besuchermuster verwenden, das auch nicht 100% SRP ist, aber es ist mehr OCP als ein Schalterfall.
quelle