it-swarm.com.de

Stellen Sie sicher, dass jede Klasse nur eine Verantwortung hat. Warum?

Laut Microsoft-Dokumentation, dem Wikipedia-Artikel SOLID Principe-Artikel) oder den meisten IT-Architekten müssen wir sicherstellen, dass jede Klasse nur eine Verantwortung trägt. Ich würde gerne wissen, warum, denn wenn alle damit einverstanden zu sein scheinen Regel scheint niemand über die Gründe dieser Regel zuzustimmen.

Einige zitieren eine bessere Wartung, andere sagen, es biete einfache Tests oder mache die Klasse robuster oder sicherer. Was ist richtig und was bedeutet es eigentlich? Warum verbessert es die Wartung, erleichtert das Testen oder macht den Code robuster?

37

Modularität. Jede anständige Sprache gibt Ihnen die Möglichkeit, Codeteile zusammenzukleben, aber es gibt keine allgemeine Möglichkeit, ein großes Codeteil zu lösen, ohne dass der Programmierer die Quelle operiert. Indem Sie viele Aufgaben in einem Codekonstrukt zusammenfassen, nehmen Sie sich und anderen die Möglichkeit, seine Teile auf andere Weise zu kombinieren, und führen unnötige Abhängigkeiten ein, die dazu führen können, dass Änderungen an einem Teil die anderen beeinflussen.

SRP ist für Funktionen genauso anwendbar wie für Klassen, aber Mainstream OOP Sprachen sind relativ schlecht darin, Funktionen zusammenzukleben.

57
Doval

Bessere Wartung, einfache Tests und schnellere Fehlerbehebung sind nur (sehr angenehme) Ergebnisse der Anwendung von SRP. Der Hauptgrund (wie Robert C. Matin es ausdrückt) ist:

Eine Klasse sollte einen und nur einen Grund haben, sich zu ändern.

Mit anderen Worten, SRP erhöht die Änderungslokalität.

SRP fördert auch DRY Code. Solange wir Klassen haben, die nur eine Verantwortung haben, können wir sie verwenden, wo immer wir wollen. Wenn wir eine Klasse haben, die zwei Verantwortlichkeiten hat, aber wir brauchen nur einer von ihnen und der zweite stört, wir haben 2 Möglichkeiten:

  1. Kopieren Sie die Klasse in eine andere und erstellen Sie möglicherweise sogar eine weitere Mutante mit mehreren Verantwortlichkeiten (erhöhen Sie die technische Verschuldung ein wenig).
  2. Teilen Sie die Klasse und machen Sie sie so, wie sie eigentlich sein sollte, was aufgrund der umfangreichen Nutzung der ursprünglichen Klasse teuer sein kann.
30

Ist einfach, Code zu erstellen, um ein bestimmtes Problem zu beheben. Es ist komplizierter, Code zu erstellen, der dieses Problem behebt und spätere Änderungen sicher vornimmt. SOLID bietet eine Reihe von Methoden, die den Code verbessern.

Welches ist richtig: Alle drei. Sie alle sind Vorteile der Verwendung einer einzelnen Verantwortung und der Grund, warum Sie sie verwenden sollten.

Was sie bedeuten:

  • Bessere Wartung bedeutet, dass es einfacher zu ändern ist und sich nicht so oft ändert. Da weniger Code vorhanden ist und sich dieser Code auf etwas Bestimmtes konzentriert, muss die Klasse nicht geändert werden, wenn Sie etwas ändern müssen, das nicht mit der Klasse zusammenhängt. Wenn Sie die Klasse ändern müssen, müssen Sie sich nur um diese Klasse und nichts anderes kümmern, solange Sie die öffentliche Schnittstelle nicht ändern müssen.
  • Einfaches Testen bedeutet weniger Tests, weniger Setup. Es gibt nicht so viele bewegliche Teile in der Klasse, daher ist die Anzahl möglicher Fehler in der Klasse geringer und daher weniger Fälle, die Sie testen müssen. Es müssen weniger private Felder/Mitglieder eingerichtet werden.
  • Aufgrund der beiden oben genannten erhalten Sie eine Klasse, die sich weniger ändert und weniger ausfällt und daher robuster ist.

Versuchen Sie, eine Weile nach dem Prinzip Code zu erstellen, und wiederholen Sie diesen Code später, um einige Änderungen vorzunehmen. Sie werden den massiven Vorteil sehen, den es bietet.

Sie tun dasselbe für jede Klasse und erhalten am Ende mehr Klassen, die alle SRP entsprechen. Dies macht die Struktur unter dem Gesichtspunkt der Verbindungen komplexer, aber die Einfachheit jeder Klasse rechtfertigt dies.

21
Miyamoto Akira

Hier sind die Argumente, die meiner Ansicht nach die Behauptung stützen, dass das Prinzip der Einzelverantwortung eine gute Praxis ist. Ich biete auch Links zu weiterer Literatur, in der Sie noch detailliertere Argumente lesen können - und beredter als meine:

  • Bessere Wartung : Idealerweise muss immer dann, wenn sich eine Funktionalität des Systems ändern muss, nur eine Klasse geändert werden. Eine klare Zuordnung zwischen Klassen und Verantwortlichkeiten bedeutet, dass jeder am Projekt beteiligte Entwickler identifizieren kann, um welche Klasse es sich handelt. (Wie @ MaciejChałapuk bemerkt hat, siehe Robert C. Martin, "Clean Code" .)

  • Einfacheres Testen : Idealerweise sollten Klassen eine möglichst minimale öffentliche Schnittstelle haben, und Tests sollten nur diese öffentliche Schnittstelle ansprechen. Wenn Sie nicht klar testen können, weil viele Teile Ihrer Klasse privat sind, ist dies ein klares Zeichen dafür, dass Ihre Klasse zu viele Verantwortlichkeiten hat und dass Sie sie in kleinere Unterklassen aufteilen sollten. Bitte beachten Sie, dass dies auch für Sprachen gilt, in denen es keine "öffentlichen" oder "privaten" Klassenmitglieder gibt. Eine kleine öffentliche Schnittstelle bedeutet, dass dem Client-Code sehr klar ist, welche Teile der Klasse er verwenden soll. (Siehe Kent Beck, "Test-Driven Development" für weitere Details.)

  • Robuster Code : Ihr Code schlägt nicht mehr oder weniger oft fehl, weil er gut geschrieben ist. Aber wie bei jedem Code ist das ultimative Ziel nicht mit der Maschine zu kommunizieren, sondern mit anderen Entwicklern (siehe Kent Beck, "Implementierungsmuster" , Kapitel 1. ) Eine eindeutige Codebasis ist leichter zu begründen, sodass weniger Fehler eingeführt werden und weniger Zeit zwischen dem Erkennen und Beheben eines Fehlers vergeht.

4
logc

Es gibt eine Reihe von Gründen, aber der, den ich mag, ist der Ansatz, den viele der frühen UNIX-Programme verwenden: Machen Sie eine Sache gut. Es ist schwer genug, dies mit einer Sache zu tun, und es wird immer schwieriger, je mehr Dinge Sie versuchen.

Ein weiterer Grund ist die Begrenzung und Kontrolle von Nebenwirkungen. Ich liebte meinen kombinierten Kaffeemaschinen-Türöffner. Leider lief der Kaffee normalerweise über, wenn ich Besucher hatte. Ich habe vergessen, die Tür zu schließen, nachdem ich neulich Kaffee gemacht hatte und jemand sie gestohlen hat.

Aus psychologischer Sicht können Sie jeweils nur wenige Dinge im Auge behalten. Allgemeine Schätzungen sind sieben plus oder minus zwei. Wenn eine Klasse mehrere Dinge tut, müssen Sie alle gleichzeitig verfolgen. Dies verringert Ihre Fähigkeit, zu verfolgen, was Sie tun. Wenn eine Klasse drei Dinge tut und Sie nur eine davon möchten, können Sie Ihre Fähigkeit, den Überblick zu behalten, erschöpfen, bevor Sie tatsächlich etwas mit der Klasse tun.

Wenn Sie mehrere Dinge tun, erhöht sich die Codekomplexität. Über den einfachsten Code hinaus erhöht eine zunehmende Komplexität die Wahrscheinlichkeit von Fehlern. Unter diesem Gesichtspunkt möchten Sie, dass der Unterricht so einfach wie möglich ist.

Das Testen einer Klasse, die eines tut, ist viel einfacher. Sie müssen nicht überprüfen, ob das zweite, was die Klasse tut, bei jedem Test passiert ist oder nicht. Sie müssen auch die fehlerhaften Bedingungen nicht beheben und erneut testen, wenn einer dieser Tests fehlschlägt.

3
BillThor

Weil Software organisch ist. Die Anforderungen ändern sich ständig, sodass Sie Komponenten mit möglichst wenig Kopfschmerzen bearbeiten müssen. Wenn Sie die Prinzipien von SOLID) nicht befolgen, erhalten Sie möglicherweise eine konkrete Codebasis.

Stellen Sie sich ein Haus mit einer tragenden Betonwand vor. Was passiert, wenn Sie diese Wand ohne Unterstützung herausnehmen? Das Haus wird wahrscheinlich einstürzen. In Software wollen wir das nicht, deshalb strukturieren wir Anwendungen so, dass Sie Komponenten einfach verschieben/ersetzen/ändern können, ohne großen Schaden zu verursachen.

2
CodeART

Insbesondere bei einem so wichtigen Prinzip wie der Einzelverantwortung würde ich persönlich erwarten, dass es viele Gründe gibt, warum Menschen dieses Prinzip übernehmen.

Einige dieser Gründe könnten sein:

  • Wartung - SRP stellt sicher, dass sich das Ändern der Verantwortung in einer Klasse nicht auf andere Verantwortlichkeiten auswirkt, was die Wartung vereinfacht. Das liegt daran, dass, wenn jede Klasse nur eine Verantwortung hat, die an einer Verantwortung vorgenommenen Änderungen von anderen Verantwortlichkeiten isoliert sind.
  • Testen - Wenn eine Klasse eine Verantwortung hat, ist es viel einfacher herauszufinden, wie diese Verantwortung getestet werden kann. Wenn eine Klasse mehrere Verantwortlichkeiten hat, müssen Sie sicherstellen, dass Sie die richtige testen und dass der Test nicht von anderen Verantwortlichkeiten der Klasse beeinflusst wird.

Beachten Sie auch, dass SRP mit einem Bündel von SOLID -Prinzipien) geliefert wird. Das Festhalten an SRP und das Ignorieren des Restes ist genauso schlecht wie das Nicht-Ausführen von SRP. Sie sollten SRP also nicht selbst bewerten. aber im Kontext aller SOLID Prinzipien.

1
Euphoric

Ich folge dem Gedanken: 1 Class = 1 Job.

Verwenden einer physiologischen Analogie: Motorisch (Neuronales System), Atmung (Lunge), Verdauung (Magen), Riechstoff (Beobachtung) usw. Jeder von ihnen hat eine Untergruppe von Controllern, aber jeder hat nur 1 Verantwortung, ob er verwaltet werden soll die Art und Weise, wie jedes ihrer jeweiligen Subsysteme funktioniert oder ob sie ein Endpunkt-Subsystem sind und nur eine Aufgabe ausführen, z. B. das Anheben eines Fingers oder das Wachsen eines Haarfollikels.

Verwechseln Sie nicht die Tatsache, dass es sich möglicherweise um einen Manager anstelle eines Arbeiters handelt. Einige Mitarbeiter werden schließlich zum Manager befördert, wenn die von ihnen ausgeführte Arbeit zu kompliziert geworden ist, als dass ein Prozess sie selbst erledigen könnte.

Der komplizierteste Teil meiner Erfahrung besteht darin, zu wissen, wann eine Klasse als Operator-, Supervisor- oder Manager-Prozess zu bestimmen ist. Unabhängig davon müssen Sie die Funktionalität für eine Verantwortung (Bediener, Vorgesetzter oder Manager) beobachten und kennzeichnen.

Wenn eine Klasse/ein Objekt mehr als eine dieser Typrollen ausführt, werden Sie feststellen, dass der Gesamtprozess Leistungsprobleme aufweist oder Engpässe verarbeitet.

1
GoldBishop

Der beste Weg, um die Bedeutung dieser Prinzipien zu verstehen, besteht darin, die Notwendigkeit zu haben.

Als ich ein Programmieranfänger war, habe ich nicht viel über Design nachgedacht, tatsächlich wusste ich nicht einmal, dass Designmuster existieren. Als meine Programme wuchsen, bedeutete das Ändern einer Sache das Ändern vieler anderer Dinge. Es war schwer, Fehler aufzuspüren, der Code war riesig und wiederholte sich. Es gab nicht viel von einer Objekthierarchie, die Dinge waren überall. Das Hinzufügen von etwas Neuem oder das Entfernen von etwas Altem würde zu Fehlern in den anderen Teilen des Programms führen. Siehe Abbildung.

Bei kleinen Projekten spielt es vielleicht keine Rolle, aber bei großen Projekten können die Dinge sehr albtraumhaft sein. Als ich später auf die Konzepte von Designmustern stieß, sagte ich mir: "Oh ja, das hätte die Dinge dann so viel einfacher gemacht.".

Sie können die Bedeutung von Entwurfsmustern erst wirklich verstehen, wenn die Notwendigkeit entsteht. Ich respektiere die Muster, weil ich aus Erfahrung sagen kann, dass sie die Codewartung einfach und den Code robust machen.

Genau wie Sie bin ich mir jedoch immer noch unsicher über das "einfache Testen", da ich noch nicht in Unit-Tests einsteigen musste.

1
harsimranb

Die Antwort ist, wie andere betont haben, dass alle korrekt sind und alle ineinander übergehen. Einfacher zu testen, erleichtert die Wartung, macht den Code robuster, erleichtert die Wartung und so weiter ...

All dies läuft auf einen Schlüsselprinzipal hinaus - der Code sollte so klein sein und so wenig wie nötig tun, um die Arbeit zu erledigen. Dies gilt für eine Anwendung, eine Datei oder eine Klasse ebenso wie für eine Funktion. Je mehr Dinge ein Code tut, desto schwieriger ist es, ihn zu verstehen, zu warten, zu erweitern oder zu testen.

Ich denke, es kann in einem Wort zusammengefasst werden: Umfang. Achten Sie genau auf den Umfang der Artefakte. Je weniger Dinge an einem bestimmten Punkt in einer Anwendung vorhanden sind, desto besser.

Erweiterter Anwendungsbereich = mehr Komplexität = mehr Möglichkeiten, wie etwas schief gehen kann.

1
jmoreno

Wenn eine Klasse zu groß ist, wird es schwierig, sie zu pflegen, zu testen und zu verstehen. Andere Antworten haben diesen Willen abgedeckt.

Es ist möglich, dass eine Klasse ohne Probleme mehr als eine Verantwortung hat, aber Sie stoßen bald auf Probleme mit zu komplexen Klassen.

Eine einfache Regel von „nur einer Verantwortung“ macht es jedoch einfach leichter zu wissen, wann Sie eine neue Klasse benötigen.

Die Definition von „Verantwortung“ ist zwar schwierig, bedeutet jedoch nicht „alles tun, was in der Anwendungsspezifikation angegeben ist“. Die eigentliche Fähigkeit besteht darin, das Problem in kleine Einheiten von „Verantwortung“ aufzuteilen.

1
Ian