private oder geschützte Variablen?

8

Ich lese derzeit Code Complete, wo McConnell nachdrücklich dazu aufruft, alle Variablen privat zu machen. Coincedental habe ich zufällig gerade an einem Projekt gearbeitet, bei dem ich eine private Variable ändern musste.

Die Klasse hatte eine private Variable (a String ), die angibt, wo ein Bild aus dem System-Chrome geladen werden soll. Ich musste dieses Bild ändern, ich weiß nichts über andere Sprachen, aber soweit ich weiß in Flex / AIR, gibt es keine Möglichkeit, eine private Variable zu überschreiben.

Wenn es als protected deklariert worden wäre, hätte ich einfach die Klasse erweitern und diese Variable außer Kraft setzen können. Aber da es privat war, musste ich den gesamten Code aus der Klasse kopieren und eine doppelte Klasse erstellen, mit dem einzigen Unterschied, dass diese Zeichenfolge ist.

Ich denke, das Argument ist, private zu verwenden, da es für eine lockere Kopplung zwischen Super- und Unterklassen sorgt, allerdings musste ich DRY komplett verletzen, um eine einfache String-Änderung erreichen zu können, was mir schlimmer vorkommt.

Das lässt mich denken, dass geschützt besser ist als privat. Ich möchte jedoch die richtigen Best-Practice-Methoden anwenden. Also, wenn privat besser ist, möchte ich verstehen warum.

Wenn der allgemeine Konsens ist, dass privat besser ist, kann jemand erklären warum?

    
JD Isaacks 13.07.2009, 03:49
quelle

10 Antworten

26

In diesem Fall war der Speicherort dieses Abbilds ein privates, implementierungsspezifisches Feature der Basisklasse. Ihre neuen Anforderungen bedeuteten, dass es möglich sein musste, von einer abgeleiteten Klasse zur anderen zu variieren.

Sie sollten das Memberfeld privat lassen, aber eine geschützte virtuelle Eigenschaft definieren, um sie abgeleiteten Klassen zugänglich zu machen:

%Vor%

In der abgeleiteten Klasse, die es ändern möchte:

%Vor%

Sie möchten auch die Basisklasse so ändern, dass sie die Eigenschaft verwendet, wenn sie den Bildpfad benötigt, anstatt das Feld zu verwenden. Dies ist das "Encapsulate Field" Refactoring.

    
John Saunders 13.07.2009, 03:57
quelle
4

Machen Sie Variablen private für, wenn Sie nur wissen, dass die bestimmte Klasse, in der sie definiert sind, die einzige sein wird, die diese Variablen verwendet. Wenn Sie jedoch eine Klasse erweitern möchten, sollten Sie protected verwenden. Private ist wirklich so, dass Sie keine Variablen global verwenden (also verwenden Sie Getter und Setter in Klassen), die dabei helfen, die Kopplung zu lockern. Geschützt ist vollkommen akzeptabel, wenn eine Klasse erweitert wird.

Im Allgemeinen würde ich sagen, dass der Zugriffstyp verwendet wird, der die Variable meistens außerhalb von Klassen und / oder Paketen versteckt.

    
AlbertoPL 13.07.2009 03:53
quelle
2
  

Wenn es als geschützt bezeichnet wurde, I   hätte einfach die Klasse erweitern können,   und diese Variable überschreiben. Aber   da es privat war, musste ich kopieren   der gesamte Code aus der Klasse und erstellen   eine doppelte Klasse mit dem einzigen   Unterschied ist diese Zeichenfolge.

Und wenn es einen Setter für den Bildort gegeben hätte, hätten Sie überhaupt keine Unterklasse (oder eine neue Klasse) benötigt.

Und wenn Sie, anstatt das Bild ändern zu wollen, eine andere kleine Änderung gewollt hätten, dann wäre vielleicht eine andere API-geschützte / virtuelle Version hilfreich gewesen. Oder vielleicht nicht. Mein einziger Punkt ist, dass es schwierig ist, ein so nebulöses Beispiel wie dieses zu betrachten und allgemeine Weisheit daraus abzuleiten.

Es gibt einen Kompromiss zwischen der Flexibilität, die eine Klasse Ihnen in Bezug auf ihr Verhalten und ihre Erweiterbarkeit gibt, und dem Aufwand für das Entwerfen und Testen der Klasse (und weitere Interaktionen zwischen verständlich, gut dokumentiert usw.). die Klasse ist). Diese Design-Trade-Offs können nicht im Vakuum bewertet werden, sondern müssen im Kontext bewertet werden. Wie wahrscheinlich sind die verschiedenen Merkmale / Verhaltensweisen / Erweiterungen / Änderungen, die eine Klasse möglicherweise tatsächlich unterstützen könnte? Die gut durchdachte Klasse verfügt über Erweiterungen für häufig erforderliche Szenarien und weist keine unnötigen Erweiterungen und APIs auf. (Und für die Erweiterungen, die da sind, gibt es eine Wahl zwischen einfachen 'Setter' und komplexeren geschützten / virtuellen / Unterklassen-Erweiterbarkeit ... Letzteres ist kein Kompromiss, um leicht zu entscheiden.)

Ich weiß nicht, ob dies Ihre spezifische Frage gut beantwortet (oder überhaupt), aber so wie ich Ihre Frage gelesen habe, hatte ich das Gefühl, dass Sie meinen, dass "es für Klassen besser ist, Schweizer-Armee-Messer zu sein weil Erweiterbarkeit / Anpassbarkeit gut ist ", und ich wollte darauf hinweisen, dass diese" guten "Dinge mit Kompromissen einhergehen. Außerdem scheint Ihre Frage zu implizieren, dass es sich bei dieser Situation um "privat" versus "geschützt" und "absondern" handelt, während ich denke, dass eine einfache "Setter-Methode" eine ausreichende API-Änderung wäre.

    
Brian 13.07.2009 04:15
quelle
2

Als ich anfing, in OO zu arbeiten, habe ich alles public oder protected gemacht und herausgefunden: "Warum sollte ich einschränken, was andere Leute mit meinem Code machen wollten?"

Als ich mehr Erfahrung gesammelt habe, sind zwei Dinge passiert:

  1. Moderne IDEs kamen und machten es lächerlich leicht zu ändern Code.
  2. Ich musste viel halten böser Code, der in erweitert wurde Wege, die seine Designer nicht beabsichtigt hatten.

Jetzt ist mein Ansatz: Mach es private , bis du public (oder protected ) machen musst - und denke auch dann darüber nach, ob das wirklich die richtige Lösung ist.

Eine gute protected -Methode ist ein intentionaler Erweiterungspunkt, der vom Designer angegeben wird. Ich habe festgestellt, dass das Entwerfen für die Erweiterbarkeit tatsächlich ziemlich schwierig ist, und Sie müssen es tun - wenn Sie es einfach offen lassen und hoffen, dass Sie nach Wartungsalarm auf der Straße fragen.

    
David Moles 15.07.2009 14:14
quelle
1

"Best Practice" ist selbst ein subjektiver Begriff, während es viele Konventionen gibt, die dazu dienen, den eigenen Code zu verbessern. Der Wert jedes einzelnen muss den Anforderungen des Problems gegenübergestellt werden, das Sie zu lösen versuchen.

Die Deklaration dieser Variable als privat sollte als Ausdruck der Entwicklerabsichten für die Variable (d. h. interne Verwendung) verstanden werden, was bedeutet, dass Sie entweder einen anderen Erweiterungspunkt oder einen doppelten Code suchen müssen.

Aus der Sicht eines API-Designs sollte man private verwenden, um Implementierungsdetails von Aufrufern zu isolieren und um Erben den Inhalt zu geben,

    
Crippledsmurf 13.07.2009 04:11
quelle
1

Privat ist, IMO, immer zuerst am besten und dann, wenn nötig, öffentlich / geschützt. Es ist viel einfacher, eine neue Methode zu erstellen, als zu versuchen, die Funktionalität zu entfernen, von der jemand abhängig war.

In diesem Fall würde ich meinen, der beste Ansatz wäre immer noch gewesen, einfach einen Setter beizubehalten. Gab es andere Funktionen, die Ihre Unterklasse bereitstellen musste, oder hätten Sie gerade eine neue Instanz erstellen können, den Pfad festlegen und damit fertig sein können?

    
Samm Bennett 13.07.2009 06:42
quelle
0

Alles, was Teil der Implementierung der Klasse ist, muss privat sein, so dass Sie die Freiheit haben, es zu ändern, wenn es nötig ist.

In dem von Ihnen erwähnten Beispiel wurde die Schnittstelle der Klasse möglicherweise nicht vollständig definiert, da Sie eine private Eigenschaft der Klasse ändern müssen. Wenn Sie die Kontrolle über den Code haben, können Sie die Eigenschaft schützen oder Funktionen hinzufügen, um den Wert zu erhalten und festzulegen.

    
Aragorn 13.07.2009 04:03
quelle
0

Machen Sie es privat, bis es geschützt werden muss. Dies ist ein Abstraktionsproblem bei Sprachen wie C #, C ++ und Java, bei denen protected / private an die Implementierung gebunden ist. Private Mitglieder können sicher automatisch inline geschaltet werden, geschützte dagegen nicht. Dies ist ähnlich dem Abstraktionsproblem in C # und C ++ mit Monomorphismus und Polymorphismus, die das virtuelle Schlüsselwort benötigen.

Dies macht im Wesentlichen ein fragiles Basisklassenproblem. Alles als geschützt / virtuell zu definieren ist die sicherste Wiederverwendung, behindert aber Optimierungen. Am effizientesten ist es, alles als privat / nicht-virtuell zu definieren.

In einer Sprache wie Eiffel erkennt der Compiler automatisch, ob Funktionen inline sein können und erkennt automatisch, ob ein Feature polymorph oder monomorph ist. Ссылка

    
clemahieu 13.07.2009 16:07
quelle
0

Geschützte Elemente sind Teil der API, da abgeleitete Klassen in anderen Paketen (d. h. Paketen außerhalb der Kontrolle Ihrer Organisation) diese erkennen können. Als solche sind sie eine Verpflichtung. Der Rat, private Beträge der Beratung vorzuziehen, um unnötige Verpflichtungen zu vermeiden. Sie können immer ein weniger sichtbares Element sichtbar machen, aber Sie können nicht immer das Gegenteil tun.

    
Willie Wheeler 23.01.2010 21:17
quelle
-1

Ich bin vielleicht der Einzige, der mit dem übereinstimmt, was der Autor meint. Die Idee, eine Superklasse öffnen zu müssen, um Änderungen an einem Accessor vorzunehmen, ist möglicherweise nicht einfach und möglicherweise nicht immer eine Option. Die Private-to-it-not-to-be-protected-Methode ist lächerlich und bedeutet letztlich, dass Sie keinen Grund hatten, privat zu arbeiten.

Der wahre Grund, warum Sie ein Mitglied privat halten möchten, ist, dass eine Instanz einer Unterklasse keinen unerwarteten Zugriff auf die Mitglieder einer Instanz einer Oberklasse haben darf, die gesperrt bleiben soll. Der unglückliche Nebeneffekt ist die fehlende Erweiterbarkeit. Die von John Sanders am häufigsten gewählte Lösung ist wahrscheinlich die beste Vorgehensweise, da sie dieses Problem anspricht.

Es ist mir jedoch gelungen, Tausende von Klassen mit häufiger Verwendung von geschützten (und fast keinen privaten) Variablen zu programmieren, und ich hatte nie etwas, was ich mit unerwarteter Verwendung als Problem bezeichnen würde. Es scheint, dass das gleiche erreicht werden kann, indem man einfach wählt, nicht so zu codieren, dass man mit anderen Klassen-geschützten Werten herumhantiert.

Abschließend sage ich:

  • Behalten Sie die Codierung mit protected bei, aber denken Sie daran, dass dies sensible Daten für Unterklassen öffnet.
  • Nutzen Sie die Vorteile der einfachen Erweiterbarkeit, aber denken Sie daran, eine 'ist-a' -Beziehung zwischen Ihren Super- und Unterklassen beizubehalten, so dass das Verhalten jedes einzelnen der Intension der Methode treu bleibt.
  • Verwenden Sie die private Variable / Protected Getter-Technik, wenn Sie hardcore sind oder zusätzliche Sicherheit brauchen.
Mims H. Wright 04.09.2009 17:18
quelle

Tags und Links