Frage

Ich verwende Vererbung selten, aber wenn ich tun, ich benutze nie Attribute geschützt, weil ich denke, es ist die Verkapselung der geerbten Klassen bricht.

Haben Sie geschützte Attribute verwenden? was tun Sie sie für?

War es hilfreich?

Lösung

In diesem Interview auf Design by Bill Venners, Joshua Bloch, den Autor von < em> Effective Java sagt:

  

Trusting Subklassen

     

Bill Venners: Sollte ich vertraue Subklassen inniger als   Nicht-Subklassen? Zum Beispiel mache ich   es einfacher für eine Unterklasse   Umsetzung zu brechen mich als ich   würde für eine Nicht-Unterklasse? Im   Insbesondere, wie fühlen Sie sich über   geschützte Daten?

     

Josh Bloch: , um etwas zu schreiben, das sowohl ableitbare und robust   gegen eine bösartige Unterklasse ist   eigentlich eine ziemlich schwierige Sache zu tun,   Angenommen Sie haben die Unterklasse Zugang geben   auf Ihre internen Datenstrukturen. Wenn   die Unterklasse haben keinen Zugriff auf   Alles, was ein normaler Benutzer   nicht der Fall, dann ist es schwieriger für die   Unterklasse zu tun Schaden. Aber es sei denn, Sie   Machen Sie alle Ihre Methoden endgültig, die   Unterklasse kann immer noch brechen Sie Ihre   Verträge nur durch die falsche tun   Dinge als Antwort auf Verfahren   Aufruf. Das ist genau, warum die   sicherheitskritische Klassen wie String   Finale sind. Sonst könnte jemand   eine Unterklasse schreiben, die Strings macht   erscheinen wandelbar, welche wäre   ausreichende Sicherheit zu brechen. so können Sie   müssen Ihre Subklassen vertrauen. Wenn du   nicht vertrauen ihnen, dann können Sie nicht zulassen,   sie, weil Subklassen kann so leicht   verursachen eine Klasse zu verletzen ihre   Verträge.

     

Soweit geschützten Daten im Allgemeinen,   es ist ein notwendiges Übel. Es sollte sein   auf ein Minimum beschränkt. Die meisten geschützten Daten   und geschützte Verfahren betragen   Begehung einer Implementierung   Detail. Ein geschütztes Gebiet ist ein   Implementierung Detail, dass Sie   Sichtbarmachung zu Subklassen. selbst ein   geschützte Methode ist ein Stück   interne Struktur, die Sie machen   sichtbar zu Subklassen.

     

Der Grund, warum Sie es sichtbar zu machen, ist, dass   ist es oft notwendig, um zu ermöglichen,   Subklassen ihre Arbeit zu tun, oder zu tun   es effizient. Aber sobald du getan hast   es, sind Sie dazu verpflichtet. Ist das jetzt   etwas, das Sie nicht erlaubt sind   ändern, auch wenn Sie später mehr finden   effiziente Implementierung, die keine   mehr beinhaltet die Verwendung einer   insbesondere Feld oder eine Methode.

     

So alle anderen Dinge gleich sind, Sie   sollten keine geschützten Mitglieder   überhaupt. Aber das heißt, wenn Sie zu haben   wenige, dann können Sie Ihre Klasse nicht verwendet werden   als Superklasse, oder zumindest nicht als   eine effiziente Superklasse. oft Sie   herauszufinden, nach der Tat. Meine Philosophie   ist als einige geschützte Mitglieder haben als   möglich, wenn Sie die erste schreiben   Klasse. Dann versuchen Sie es zu Unterklasse. Sie   herausfinden kann, dass ohne eine besondere   geschützte Methode werden alle Subklassen   müssen einige schlechte Sache tun.

     

Als Beispiel wenn man sich   AbstractList, finden Sie, dass es finden   ist ein geschütztes Verfahren ein löschen   Bereich der Liste in einem Schuss   (removeRange). Warum ist dort das?   Da das normale Idiom entfernen ein   Bereich, bezogen auf die öffentliche API, ist zu   rufen subList eine Unter List zu bekommen,   und rufen Sie dann clear auf, dass   Unter List. Ohne diese besondere   geschützte Verfahren werden jedoch die einzigen   Sache, dass clear tun können, ist   immer wieder einzelne Elemente entfernen.

     

Denken Sie darüber nach. Wenn Sie ein Array   Darstellung, was es tun? Es   wird wiederholt, um die Anordnung zusammenbrechen,   tun, um N Arbeit N-mal. So wird es   nehmen eine quadratische Menge an Arbeit,   statt der linearen Menge an Arbeit   dass es sollte. Durch die Bereitstellung dieser   geschützte Methode lassen wir jede   Implementierung, die können effizient   eine ganze Reihe löschen, dies zu tun. Und   jede vernünftige List Implementierung   kann löschen effizienter eine Reihe   alles auf einmal.

     

Dass wir müssten diese geschützt   Methode ist etwas, das Sie haben würde   sein Weg klüger als ich to wissen up   Vorderseite. Grundsätzlich ist implementiert die   Ding. Dann, als wir begannen, Unterklasse   es haben wir erkannt, dass Bereich löschen war   quadratisch. Wir konnten nicht leisten, so   Ich habe in der geschützten Methode. Ich denke   das ist der beste Ansatz mit   geschützte Methoden. Setzen Sie in nur   möglich, und dann mehr nach Bedarf hinzufügen.   Geschützte Methoden darstellen   Verpflichtungen Entwürfe, die Sie vielleicht   ändern möchten. Sie können jederzeit hinzufügen   geschützte Methoden, aber Sie können nicht nehmen   sie aus.

     

Bill Venners:? Und geschützte Daten

     

Josh Bloch: Die gleiche, aber noch mehr. Geschützte Daten sind noch   gefährlich in Bezug auf die Unordnung zu Ihrer   Daten Invarianten. Wenn Sie jemanden geben   sonst Zugriff auf einige interne Daten,   sie haben freie Herrschaft über sie.

Kurzversion:. Es bricht Kapselung, aber es ist ein notwendiges Übel, das auf einem Minimum gehalten werden sollte,

Andere Tipps

C #:

Ich verwende für abstrakte oder virtuelle Methoden geschützt, die ich Basisklassen wollen außer Kraft zu setzen. Ich mache auch ein Verfahren geschützt, wenn sie von Basisklassen aufgerufen werden können, aber ich will nicht, dass es außerhalb der Klassenhierarchie genannt.

Sie können sie für statische müssen (oder ‚global‘) Attribut, das Sie mögen, dass Ihre Unterklassen oder Klassen aus demselben Paket (wenn es über Java ist) von profitieren.

Diese static final Attribute eine Art ‚konstanten Wert‘ darstellen, hat selten eine Getter-Funktion, so dass ein geschütztes statisches Attribut final Sinn in diesem Fall machen könnte.

Scott Meyers sagt nicht Verwendung geschützt Attribute in Effective C ++ (3. Aufl.):

  

Artikel 22:. Deklarieren private Datenelemente

Der Grund ist der gleiche Sie geben: es bricht Verkapselungen. Die Folge davon ist, dass ansonsten lokale Änderungen am Layout der Klasse könnten abhängige Typen brechen und in Veränderungen in vielen anderen Orten führen.

Es gibt nie gute Gründe geschützt Attribute zu haben. Eine Basisklasse muss in der Lage sein, auf Zustand abhängen, was bedeutet, den Zugriff auf Daten durch Accessormethoden einzuschränken. Sie können nicht, dass jemand Zugriff auf Ihre privaten Daten geben, auch Kinder.

Das protected Schlüsselwort ist ein konzeptioneller Fehler und Sprache Design Pfusch und mehrere modernen Sprachen, wie Nim und Ceylon (siehe http://ceylon-lang.org/documentation/faq/language-design/#no_protected_modifier ), die sorgfältig entworfen wurde, und nicht nur das Kopieren häufige Fehler, don‘ t haben eine solche Schlüsselwort.

Es ist nicht Mitglieder geschützt, die Verkapselung bricht, ist es Mitglieder ausgesetzt wird, die nicht sein sollte ausgesetzt, die Verkapselung bricht ... es spielt keine Rolle, ob sie geschützt sind oder öffentlich. Das Problem mit protected ist, dass es verbohrt und irreführend ... erklärt Mitglieder protected (statt private) ist sie nicht zu schützen, ist es das Gegenteil der Fall ist, genau wie public tut. Ein geschütztes Mitglied, zugänglich außerhalb der Klasse zu sein, ist in der Welt ausgesetzt und so muss ihre Semantik für immer aufrecht erhalten werden, so wie es der Fall für public ist. Die ganze Idee von „geschützt“ ist Unsinn ... Verkapselung ist nicht Sicherheit, und das Schlüsselwort fördert nur die Verwirrung zwischen den beiden. Sie können durch die Vermeidung alle Verwendungen von protected in Ihren eigenen Klassen ein wenig helfen - wenn etwas ein interner Teil der Umsetzung ist, ist nicht Teil der Semantik der Klasse und kann sich in Zukunft ändern, dann machen es privat oder intern Ihr Paket, Modul, Montag, etc. Wenn es ein unveränderlicher Teil der Klasse Semantik ist, dann macht sie öffentlich, und dann werden Sie nicht Benutzer Ihrer Klasse ärgern, die, dass es ein nützliches Mitglied in der Dokumentation sehen können, aber‘ t verwenden es, wenn sie ihre eigenen Instanzen erstellen und können sie durch Subclassing erhalten.

Ich benutze keine geschützten Attribute in Java, weil sie dort nur Paket geschützt sind. Aber in C ++, werde ich sie in abstrakten Klassen verwenden, so dass die erbenden Klasse direkt zu übernehmen.

Im Allgemeinen wird nicht Sie wirklich wollen nicht geschützte Datenelemente verwenden. Dies ist doppelt wahr, wenn Sie eine API zu schreiben. Sobald jemand aus Ihrer Klasse erbt kann man nie wirklich Wartung tun und sie irgendwie nicht in einer seltsamen und manchmal wilden Art und Weise zu brechen.

Ich denke, geschützte Attribute eine schlechte Idee sind. Ich benutze Check diese Regel mit meinen Java-Entwicklungsteams zu erzwingen.

ich an einem Projekt vor kurzem arbeitet, waren das „geschützte“ Mitglied eine sehr gute Idee war. Die Klasse hiearchy war so etwas wie:

[+] Base
 |
 +--[+] BaseMap
 |   |
 |   +--[+] Map
 |   |
 |   +--[+] HashMap
 |
 +--[+] // something else ?

Die Basis implementiert eine std :: list aber sonst nichts. Der direkte Zugriff auf die Liste wurde dem Benutzer verboten, aber als die Basisklasse unvollständig war, berief sie sich ohnehin auf abgeleiteten Klassen, das indirection in die Liste zu implementieren.

Der Indirektionsoperator könnte aus mindestens zwei Varianten: std :: map und stdext :: hash_map. Beiden Karten werden auf die gleiche Weise verhalten, aber die Tatsache, muss die hash_map den Schlüssel sein hashable (in VC2003, gießbare size_t).

So BaseMap implementiert eine TMap als Templat-Typ, der eine Karte artige Behälter war.

Karte und HashMap waren zwei abgeleiteten Klassen von BaseMap, ein spezialisiert BaseMap auf std :: map, und die andere auf stdext :: hash_map.

So:

  • war Basis nicht als solches verwendbar (keine öffentlichen Accessoren!) Und nur gemeinsame Merkmale und Code zur Verfügung gestellt

  • BaseMap benötigt einfach zu lesen / schreiben, um eine std :: list

  • Karte und HashMap benötigten einfachen Lese- / Schreibzugriff auf die TMap definierte in BaseMap.

Für mich war die einzige Lösung für die std :: Liste und die Membervariablen TMap geschützt zu verwenden. Es gab keinen Weg ich diese „privaten“ setzen würde, weil ich sowieso alle aussetzen würde oder fast alle ihre Funktionen durch Lese- / Schreibzugriffs trotzdem.

Am Ende, ich denke, dass, wenn Sie en Sie Ihre Klasse in mehrere Objekte unterteilt, jede Ableitung benötigte Funktionen zu seiner Mutter Klasse hinzufügen, und nur die abgeleitete Klasse wirklich verwendbar sind, dann geschützt ist der Weg zu gehen. Die Tatsache, das „geschützte Mitglied“ war eine Klasse, und so war fast unmöglich zu „brechen“, geholfen.

Aber ansonsten geschützt sollten so weit wie möglich vermieden werden (d .: Verwendung standardmäßig privat und öffentlich, wenn Sie das Verfahren aussetzen müssen).

Ich benutze sie. Kurz gesagt, es ist ein guter Weg, wenn Sie einige Attribute geteilt haben wollen. Zugegeben, könnten Sie setzen / erhalten Funktionen für sie schreiben, aber wenn es keine Validierung ist, was ist dann der Punkt? Es ist auch schneller.

Bedenken Sie: Sie haben eine Klasse, die Ihre Basisklasse ist. Es hat einige Attribute, die Sie wan't in den untergeordneten Objekte zu verwenden. Sie könnten eine get / set-Funktion für jeden schreiben, oder Sie können sie gerade eingestellt haben.

Mein typisches Beispiel ist eine Datei / Stream-Handler. Sie wollen den Handler für den Zugriff auf (das heißt Dateideskriptor), aber Sie wollen es von anderen Klassen verstecken. Es ist viel einfacher, als einen Satz zu schreiben / get-Funktion für sie.

In der Regel ja. Eine geschützte Methode ist in der Regel besser.

Im Einsatz gibt es ein Maß an Einfachheit gegeben durch die Verwendung eines geschütztes letztes Variable für ein Objekt, das von allen Kindern einer Klasse geteilt wird. Ich habe immer davon abraten mit Primitiven oder Sammlungen verwenden, da die Verträge sind unmöglich für diese Typen zu definieren.

In letzter Zeit habe ich getrennte Sachen kommen Sie mit Primitiven und rohen Sammlungen von Sachen tun Sie mit gut ausgebildeten Klassen zu tun. Primitives und Sammlungen sollten immer privat sein.

Außerdem habe ich begonnen Variablen gelegentlich aussetzt öffentlichen Teil, wenn sie endgültig sind Gebenes und wohlgeformte Klassen sind, die nicht zu flexibel sind (auch hier nicht Primitiven oder Sammlungen).

Das ist nicht irgendeine dumme Abkürzung, dachte ich, es ist ziemlich ernst und entschied es gibt absolut keinen Unterschied zwischen einem öffentlich letzt Variable ein Objekt und einem Getter ausgesetzt wird.

Es hängt davon ab, was Sie wollen. Wenn Sie eine schnelle Klasse dann Daten wollen, sollten geschützt werden und die Verwendung geschützt und öffentliche Methoden. Weil ich denke, Sie sollten davon ausgehen, dass die Benutzer, die recht gut aus der Klasse kennen Ihre Klasse ableiten oder zumindest haben sie Ihr Handbuch an der Funktion, lesen sie gehen außer Kraft zu setzen.

Wenn Ihre Benutzer verwirren mit Ihrer Klasse es nicht Ihr Problem. Jeder böswilliger Benutzer kann die folgenden Zeilen hinzufügen, wenn einer Ihrer virtuals überschrieben:

(C #)

static Random rnd=new Random();
//...
if (rnd.Next()%1000==0) throw new Exception("My base class sucks! HAHAHAHA! xD");
//...

Sie können nicht jede Klasse abdichten, dies zu verhindern.

Natürlich, wenn Sie eine Einschränkung auf einige Ihrer Felder wollen, dann verwenden Accessorfunktionen oder Eigenschaften oder etwas, das Sie wollen und machen das Feld privat, weil es keine andere Lösung gibt ...

Aber ich persönlich nicht um jeden Preis an die OOP-Prinzipien halten mag. Insbesondere Eigenschaften mit dem einzigen Zweck zu machen, um mit privaten Datenelementen.

(C #):

private _foo;
public foo
{
   get {return _foo;}
   set {_foo=value;}
}

Das war meine persönliche Meinung.

Aber das tun, was Ihr Chef werden (wenn er private Felder will als das.)

Ich verwende geschützte Variablen / Attribute in Basisklassen, die ich weiß, ich habe nicht vor in den Methoden zum Ändern. Auf diese Weise haben Subklassen vollen Zugriff auf ihre geerbten Variablen und haben nicht die (künstlich geschaffene) Kopf gehen durch Getter / Setter auf sie zuzugreifen. Ein Beispiel ist eine Klasse, einen zugrundeliegenden I / O-Strom verwendet wird; gibt es wenig Grund direkten Zugang zum zugrunde liegenden Stream nicht Subklassen zu ermöglichen.

Dies ist für Membervariablen in Ordnung, die in direkter einfacher Weise innerhalb der Basisklasse und alle Unterklassen verwendet werden. Aber für eine Variable, die eine kompliziertere Verwendung hat (zum Beispiel den Zugriff auf verursacht es Nebenwirkungen in anderen Mitgliedern innerhalb der Klasse), eine direkt zugängliche Variable nicht geeignet ist. In diesem Fall kann es aus privatem und öffentlichem / protected Getter / Setter werden kann stattdessen zur Verfügung gestellt werden. Ein Beispiel hierfür ist ein interner Puffermechanismus durch die Basisklasse bereitgestellt, wobei die Puffer Zugriff direkt von einer Unterklasse, die Integrität der Algorithmen, die von der Basisklasse verwendet gefährden würde sie verwalten.

Es ist eine Design-Urteil Entscheidung, basierend auf, wie einfach die Membervariable ist, und wie es so in zukünftigen Versionen zu erwarten ist.

Die Einkapselung ist groß, aber es kann zu weit genommen werden. Ich habe Klassen, die eigenen Methoden zugegriffen seine Mitgliedsvariablen privat gesehen mit nur Getter / Setter-Methoden. Das ist übertrieben, denn wenn eine Klasse nicht über einen eigenen Methoden mit seinem eigenen privaten Daten vertrauen können, wer kann sie trauen?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top