Prinzip der Einzelverantwortung in Java

1. Übersicht

In diesem Tutorial werden wir das Prinzip der Einzelverantwortung als eines der SOLID-Prinzipien der objektorientierten Programmierung diskutieren.

Insgesamt werden wir uns eingehend mit diesem Prinzip und seiner Implementierung beim Entwurf unserer Software befassen. Außerdem erklären wir, wann dieses Prinzip irreführend sein kann.

* SRP = Prinzip der Einzelverantwortung

2. Prinzip der Einzelverantwortung

Wie der Name schon sagt, besagt dieses Prinzip, dass jede Klasse eine Verantwortung, einen einzigen Zweck haben sollte . Dies bedeutet, dass eine Klasse nur einen Job erledigt, was uns zu dem Schluss führt, dass sie nur einen Grund zur Änderung haben sollte .

Wir wollen keine Objekte, die zu viel wissen und sich nicht verhalten. Diese Klassen sind schwerer zu pflegen. Wenn wir beispielsweise eine Klasse haben, die wir aus verschiedenen Gründen stark ändern, sollte diese Klasse in mehrere Klassen unterteilt werden, die jeweils ein einzelnes Problem behandeln. Wenn ein Fehler auftritt, ist er sicherlich leichter zu finden.

Betrachten wir eine Klasse, die Code enthält, der den Text auf irgendeine Weise ändert. Die einzige Aufgabe dieser Klasse sollte das Bearbeiten von Text sein .

public class TextManipulator { private String text; public TextManipulator(String text) { this.text = text; } public String getText() { return text; } public void appendText(String newText) { text = text.concat(newText); } public String findWordAndReplace(String word, String replacementWord) { if (text.contains(word)) { text = text.replace(word, replacementWord); } return text; } public String findWordAndDelete(String word) { if (text.contains(word)) { text = text.replace(word, ""); } return text; } public void printText() { System.out.println(textManipulator.getText()); } }

Obwohl dies in Ordnung zu sein scheint, ist es kein gutes Beispiel für die SRP. Hier haben wir zwei Aufgaben : Bearbeiten und Drucken des Textes .

Eine Methode, mit der Text in dieser Klasse ausgedruckt wird, verstößt gegen das Prinzip der Einzelverantwortung. Zu diesem Zweck sollten wir eine weitere Klasse erstellen, die nur das Drucken von Text behandelt:

public class TextPrinter { TextManipulator textManipulator; public TextPrinter(TextManipulator textManipulator) { this.textManipulator = textManipulator; } public void printText() { System.out.println(textManipulator.getText()); } public void printOutEachWordOfText() { System.out.println(Arrays.toString(textManipulator.getText().split(" "))); } public void printRangeOfCharacters(int startingIndex, int endIndex) { System.out.println(textManipulator.getText().substring(startingIndex, endIndex)); } }

Jetzt können wir in dieser Klasse Methoden für so viele Variationen von Drucktexten erstellen, wie wir möchten, denn das ist ihre Aufgabe.

3. Wie kann dieses Prinzip irreführend sein?

Der Trick bei der Implementierung von SRP in unserer Software besteht darin, die Verantwortung jeder Klasse zu kennen.

Allerdings hat jeder Entwickler ihre Vision von der Klasse Zweck , die Dinge heikel macht. Da wir keine strengen Anweisungen zur Umsetzung dieses Prinzips haben, bleibt uns unsere Interpretation der Verantwortung überlassen.

Dies bedeutet, dass manchmal nur wir als Designer unserer Anwendung entscheiden können, ob etwas im Umfang einer Klasse liegt oder nicht.

Wenn wir eine Klasse nach dem SRP-Prinzip schreiben, müssen wir die Problemdomäne, die Geschäftsanforderungen und die Anwendungsarchitektur berücksichtigen. Es ist sehr subjektiv, was die Umsetzung dieses Prinzips schwieriger macht, als es scheint. Es wird nicht so einfach sein wie das Beispiel in diesem Tutorial.

Dies führt uns zum nächsten Punkt.

4. Zusammenhalt

Nach dem SRP-Prinzip halten sich unsere Klassen an eine Funktionalität. Ihre Methoden und Daten werden sich auf einen klaren Zweck beziehen. Dies bedeutet hohe Kohäsion sowie Robustheit, die zusammen Fehler reduzieren .

Bei der Entwicklung von Software, die auf dem SRP-Prinzip basiert, ist der Zusammenhalt von entscheidender Bedeutung, da wir so einzelne Verantwortlichkeiten für unsere Klassen finden können. Dieses Konzept hilft uns auch dabei, Klassen zu finden, die mehr als eine Verantwortung haben.

Kehren wir zu unseren TextManipulator- Klassenmethoden zurück:

... public void appendText(String newText) { text = text.concat(newText); } public String findWordAndReplace(String word, String replacementWord) { if (text.contains(word)) { text = text.replace(word, replacementWord); } return text; } public String findWordAndDelete(String word) { if (text.contains(word)) { text = text.replace(word, ""); } return text; } ...

Hier haben wir eine klare Darstellung dessen, was diese Klasse tut: Textmanipulation.

Wenn wir jedoch nicht an Zusammenhalt denken und keine klare Definition der Verantwortung dieser Klasse haben, können wir sagen, dass das Schreiben und Aktualisieren des Textes zwei verschiedene und getrennte Aufgaben sind. Ausgehend von diesem Gedanken können wir schließen, dass dies zwei getrennte Klassen sein sollten: WriteText und UpdateText .

In Wirklichkeit würden wir zwei Klassen erhalten, die eng miteinander verbunden und lose zusammenhängend sind und die fast immer zusammen verwendet werden sollten. Diese drei Methoden können unterschiedliche Operationen ausführen, dienen jedoch im Wesentlichen einem einzigen Zweck : der Textmanipulation. Der Schlüssel ist nicht zu überdenken.

Eines der Werkzeuge, die dazu beitragen können, eine hohe Kohäsion der Methoden zu erreichen, ist LCOM. Im Wesentlichen misst LCOM die Verbindung zwischen Klassenkomponenten und ihre Beziehung zueinander.

Martin Hitz und Behzad Montazeri stellten LCOM4 vor, das Sonarqube eine Zeit lang gemessen hat, seitdem aber veraltet ist.

5. Schlussfolgerung

Obwohl der Name des Prinzips selbsterklärend ist, können wir sehen, wie einfach es ist, falsch zu implementieren. Achten Sie bei der Entwicklung eines Projekts darauf, die Verantwortung jeder Klasse zu unterscheiden, und achten Sie besonders auf den Zusammenhalt.

Wie immer ist der Code auf GitHub verfügbar.