Clean Code empfiehlt, geschützte Variablen im Abschnitt "Vertikaler Abstand" des Kapitels "Formatierung" zu vermeiden:
Konzepte, die eng miteinander verbunden sind, sollten vertikal nahe beieinander gehalten werden. Offensichtlich funktioniert diese Regel nicht für Konzepte, die in separate Dateien gehören. Aber eng verwandte Konzepte sollten nicht in verschiedene Dateien aufgeteilt werden, es sei denn, Sie haben einen sehr guten Grund. Dies ist einer der Gründe, warum geschützte Variablen vermieden werden sollten .
Was ist die Begründung?
code-quality
clean-code
variables
Matsemann
quelle
quelle
Antworten:
Geschützte Variablen sollten vermieden werden, weil:
Aber wie Sie sehen, sind alle diese "tendenziell". Manchmal ist ein geschütztes Mitglied die eleganteste Lösung. Geschützte Funktionen weisen in der Regel weniger dieser Probleme auf. Es gibt jedoch eine Reihe von Faktoren, die zu einer sorgfältigen Behandlung führen. Mit allem, was diese Art von Sorgfalt erfordert, machen die Leute Fehler und in der Programmierwelt bedeutet dies Fehler und Designprobleme.
quelle
Es ist wirklich der gleiche Grund, warum Sie Globals vermeiden, nur in kleinerem Maßstab. Das liegt daran, dass es schwierig ist, überall zu finden, wo eine Variable gelesen oder noch schlimmer geschrieben wird, und dass es schwierig ist, die Verwendung konsistent zu machen. Wenn die Verwendung begrenzt ist, wie an einer offensichtlichen Stelle in der abgeleiteten Klasse geschrieben und an einer offensichtlichen Stelle in der Basisklasse gelesen , können geschützte Variablen den Code klarer und prägnanter machen. Wenn Sie versucht sind, eine Variable in mehreren Dateien beliebig oft zu lesen und zu schreiben, ist es besser, sie zu kapseln.
quelle
Ich habe das Buch nicht gelesen, aber ich kann einen Stich in die Bedeutung von Onkel Bob machen.
Wenn Sie
protected
etwas anlegen , bedeutet dies, dass eine Klasse es erben kann. Mitgliedsvariablen sollen jedoch zu der Klasse gehören, in der sie enthalten sind. Dies ist Teil der grundlegenden Kapselung. Wenn Sieprotected
eine Membervariable hinzufügen, wird die Kapselung unterbrochen, da jetzt eine abgeleitete Klasse Zugriff auf die Implementierungsdetails der Basisklasse hat. Es ist dasselbe Problem, das auftritt, wenn Sie eine Variablepublic
für eine gewöhnliche Klasse erstellen.Um das Problem zu beheben, können Sie die Variable wie folgt in eine geschützte Eigenschaft einkapseln:
Dies ermöglicht
name
das sichere Festlegen einer abgeleiteten Klasse mithilfe eines Konstruktorarguments, ohne dass Implementierungsdetails der Basisklasse verfügbar gemacht werden.quelle
protected
undpublic
Mitgliedern. WennBaseType
ein öffentliches Mitglied verfügbar gemacht wird, bedeutet dies, dass alle abgeleiteten Typen dasselbe Mitglied haben müssen, das auf die gleiche Weise funktioniert, da eineDerivedType
Instanz möglicherweise an den Code übergeben wird, der eineBaseType
Referenz empfängt und die Verwendung dieses Mitglieds erwartet. Wenn im Gegensatz dazuBaseType
einprotected
Mitglied verfügbar gemacht wird ,DerivedType
kann erwartet werden, dass es auf dieses Mitglied zugreiftbase
,base
kann jedoch nichts anderes als a seinBaseType
.Onkel Bobs Argument ist in erster Linie die Distanz: Wenn Sie ein Konzept haben, das für eine Klasse wichtig ist, bündeln Sie das Konzept zusammen mit der Klasse in dieser Datei. Nicht auf zwei Dateien auf der Festplatte aufgeteilt.
Geschützte Member-Variablen sind an zwei Stellen verteilt und sehen irgendwie wie Magie aus. Sie verweisen auf diese Variable, aber sie ist hier nicht definiert. Wo ist sie definiert? Und so beginnt die Jagd. Vermeiden Sie lieber
protected
sein Argument.Jetzt glaube ich nicht, dass diese Regel die ganze Zeit eingehalten werden muss (wie: du sollst nicht verwenden
protected
). Schauen Sie sich den Geist dessen , was er ist immer auf ... bündeln verwandte Dinge zusammen in einer Datei - verwenden Techniken und Funktionen Programmierung zu tun. Ich würde empfehlen, dass Sie nicht zu viel analysieren und sich in die Details darüber vertiefen.quelle
Einige sehr gute Antworten schon hier. Aber eins noch:
In den meisten modernen OO-Sprachen ist es eine gute Angewohnheit (in Java AFAIK ist dies erforderlich), jede Klasse in eine eigene Datei zu packen (bitte machen Sie sich keine Gedanken über C ++, wo Sie oft zwei Dateien haben).
Daher ist es praktisch unmöglich, die Funktionen in einer abgeleiteten Klasse so zu halten, dass sie auf eine geschützte Variable einer Basisklasse zugreifen, die im Quellcode der Variablendefinition "vertikal nahe" ist. Idealerweise sollten sie jedoch dort aufbewahrt werden, da geschützte Variablen für den internen Gebrauch vorgesehen sind, was den Zugriff auf Funktionen häufig zu einem "eng verwandten Konzept" macht.
quelle
Die Grundidee ist, dass ein "Feld" (Variable auf Instanzebene), das als geschützt deklariert ist, wahrscheinlich sichtbarer als es sein muss und weniger "geschützt" ist, als Sie vielleicht möchten. In C / C ++ / Java / C # gibt es keinen Zugriffsmodifikator, der der Entsprechung von "Nur für untergeordnete Klassen in derselben Assembly zugänglich" entspricht. Auf diese Weise können Sie eigene untergeordnete Klassen definieren, die auf das Feld in Ihrer Assembly zugreifen können Kindern, die in anderen Baugruppen erstellt wurden, nicht den gleichen Zugriff gewähren; C # hat interne und geschützte Modifikatoren, aber wenn Sie diese kombinieren, wird der Zugriff "intern oder geschützt", nicht "intern und geschützt". Auf ein geschütztes Feld kann also jedes Kind zugreifen, unabhängig davon, ob Sie das Kind geschrieben haben oder es jemand anderes getan hat. Geschützt ist damit eine offene Tür für einen Hacker.
Außerdem haben Felder per Definition so gut wie keine Validierung, wenn sie geändert werden. In C # können Sie einen Readonly-Wert erstellen, wodurch Werttypen effektiv konstant und Referenztypen nicht neu initialisiert werden können (aber immer noch sehr wandelbar sind), aber das war es auch schon. Selbst geschützt haben Ihre Kinder (denen Sie nicht vertrauen können) Zugriff auf dieses Feld und können es auf einen ungültigen Wert setzen, wodurch der Zustand des Objekts inkonsistent wird (etwas, das vermieden werden muss).
Die akzeptierte Möglichkeit, mit Feldern zu arbeiten, besteht darin, sie privat zu machen und mit einer Eigenschaft und / oder einer Get- und Setter-Methode darauf zuzugreifen. Wenn alle Konsumenten der Klasse den Wert benötigen, machen Sie den Getter (zumindest) öffentlich. Wenn nur Kinder es brauchen, machen Sie den Getter geschützt.
Ein anderer Ansatz, der die Frage beantwortet, ist, sich selbst zu fragen. Warum muss Code in einer untergeordneten Methode die Möglichkeit haben, meine Statusdaten direkt zu ändern? Was sagt das über diesen Code aus? Das ist das "vertikale Distanz" -Argument. Wenn ein untergeordnetes Element Code enthält, der den Status des übergeordneten Elements direkt ändern muss, sollte dieser Code möglicherweise zunächst dem übergeordneten Element gehören.
quelle
Es ist eine interessante Diskussion.
Um ehrlich zu sein, können gute Tools viele dieser "vertikalen" Probleme lindern. Meiner Meinung nach ist der Begriff "Datei" tatsächlich etwas, das die Softwareentwicklung behindert - etwas, woran das Light Table-Projekt arbeitet (http://www.chris-granger.com/2012/04/12/light- Tabelle --- ein-neues-Ide-Konzept /).
Nehmen Sie Dateien aus dem Bild, und der geschützte Bereich wird attraktiver. Das geschützte Konzept wird am deutlichsten in Sprachen wie SmallTalk - wo jede Vererbung einfach das ursprüngliche Konzept einer Klasse erweitert. Es sollte alles tun und alles haben, was die Elternklasse getan hat.
Meiner Meinung nach sollten Klassenhierarchien so flach wie möglich sein, wobei die meisten Erweiterungen aus der Komposition stammen. In solchen Modellen sehe ich keine Gründe dafür, dass private Variablen stattdessen nicht geschützt werden. Wenn die erweiterte Klasse eine Erweiterung darstellen soll, die das gesamte Verhalten der übergeordneten Klasse umfasst (was meiner Meinung nach und daher private Methoden von Natur aus als schlecht erachten), warum sollte die erweiterte Klasse dann nicht auch die Speicherung solcher Daten darstellen?
Anders ausgedrückt: In jedem Fall, in dem ich der Meinung bin, dass eine private Variable besser geeignet ist als eine geschützte, ist die Vererbung nicht die Lösung des Problems.
quelle
Wie es dort heißt, ist dies nur einer der Gründe, weshalb logisch verknüpfter Code in physisch verknüpften Entitäten (Dateien, Pakete und andere) platziert werden sollte. In kleinerem Maßstab entspricht dies dem Grund, warum Sie keine Klasse einfügen, die DB-Abfragen in das Paket mit Klassen aufnimmt, die die Benutzeroberfläche anzeigen.
Der Hauptgrund dafür, dass geschützte Variablen nicht empfohlen werden, besteht darin, dass sie dazu neigen, die Kapselung zu unterbrechen. Variablen und Methoden sollten so wenig wie möglich sichtbar sein. Weitere Informationen finden Sie in Joshua Blochs Effective Java , Punkt 13 - "Minimieren Sie die Zugänglichkeit von Klassen und Mitgliedern".
Sie sollten jedoch nicht das gesamte Ad-Litteram als Guildline verwenden. Wenn geschützte Variablen sehr schlecht sind, wurden sie nicht an erster Stelle in die Sprache eingefügt. Ein sinnvoller Ort für geschützte Felder ist imho innerhalb der Basisklasse ein Testframework (Integrationstestklassen erweitern es).
quelle
Ich finde, dass die Verwendung von geschützten Variablen für JUnit-Tests nützlich sein kann. Wenn Sie sie als privat kennzeichnen, können Sie während des Testens nicht ohne Reflektion darauf zugreifen. Dies kann hilfreich sein, wenn Sie einen komplexen Prozess durch viele Statusänderungen testen.
Sie könnten sie mit geschützten Getter-Methoden privat machen, aber wenn die Variablen nur während eines JUnit-Tests extern verwendet werden, bin ich mir nicht sicher, ob das eine bessere Lösung ist.
quelle
Ja, ich stimme zu, dass dies etwas seltsam ist, da (wie ich mich erinnere) in dem Buch auch alle nicht-privaten Variablen als etwas behandelt werden, das vermieden werden sollte.
Ich denke, das Problem mit dem protected-Modifikator ist, dass das Mitglied nicht nur Subklassen ausgesetzt ist, sondern auch für das gesamte Paket sichtbar ist. Ich denke, es ist dieser doppelte Aspekt, den Onkel Bob hier ausnimmt. Natürlich kann man geschützte Methoden und damit die geschützte Variablenqualifikation nicht immer umgehen.
Ich denke, ein interessanterer Ansatz ist es, alles öffentlich zu machen, was Sie zu kleinen Klassen zwingt, was wiederum die gesamte vertikale Distanzmetrik etwas umstritten macht.
quelle