Auf der Suche nach einem bestimmten Anwendungsfall, bei dem sowohl eine Unterklasse als auch eine Klasse innerhalb desselben Pakets auf ein geschütztes Feld oder eine geschützte Methode zugreifen müssen ...
Für mich ist ein solcher Anwendungsfall eher allgemein als spezifisch und ergibt sich aus meinen Vorlieben für:
- Beginnen Sie mit einem so strengen Zugriffsmodifikator wie möglich, und greifen Sie erst später auf schwächere Modifikatoren zurück, wenn dies als notwendig erachtet wird.
- Unit-Tests befinden sich im selben Paket wie der getestete Code.
Von oben kann ich anfangen, mit Standardzugriffsmodifikatoren für meine Objekte zu entwerfen (ich würde damit beginnen, private
aber das würde den Komponententest erschweren):
public class Example {
public static void main(String [] args) {
new UnitTest().testDoSomething(new Unit1(), new Unit2());
}
static class Unit1 {
void doSomething() {} // default access
}
static class Unit2 {
void doSomething() {} // default access
}
static class UnitTest {
void testDoSomething(Unit1 unit1, Unit2 unit2) {
unit1.doSomething();
unit2.doSomething();
}
}
}
Randnotiz im obigen Snippet Unit1
, Unit2
und UnitTest
sind verschachtelt in der Example
Einfachheit der Darstellung, sondern in einem realen Projekt, würde ich wahrscheinlich diese Klassen in separaten Dateien (und habe UnitTest
auch in einem separaten Verzeichnis ).
Wenn dann eine Notwendigkeit entsteht, würde ich die Zugriffskontrolle von Standard auf schwächen protected
:
public class ExampleEvolved {
public static void main(String [] args) {
new UnitTest().testDoSomething(new Unit1(), new Unit2());
}
static class Unit1 {
protected void doSomething() {} // made protected
}
static class Unit2 {
protected void doSomething() {} // made protected
}
static class UnitTest {
// ---> no changes needed although UnitTest doesn't subclass
// ...and, hey, if I'd have to subclass... which one of Unit1, Unit2?
void testDoSomething(Unit1 unit1, Unit2 unit2) {
unit1.doSomething();
unit2.doSomething();
}
}
}
Sie sehen, ich kann Unit-Test-Code behalten ExampleEvolved
unverändert lassen, da geschützte Methoden aus demselben Paket zugänglich sind, obwohl der Zugriff auf das Objekt keine Unterklasse ist .
Weniger Änderungen erforderlich => sicherere Modifikation; Immerhin habe ich nur Zugriffsmodifikatoren geändert und nicht geändert, welche Methoden Unit1.doSomething()
und Unit2.doSomething()
Aktionen ausgeführt wurden. Daher ist es nur natürlich zu erwarten, dass Unit-Test-Code ohne Änderungen weiter ausgeführt wird.
protected
es sich nur um Unterklassen handelt? Ehrlich gesagt hatte ich lange Zeit den Eindruck, dass dies das Verhalten istprotected
nur Klasse und Unterklasse undinternal
bibliotheks- / paketweit. Es hat auchprotected internal
das Äquivalent zu Javaprotected
.IMHO, das war eine schlechte Designentscheidung in Java.
Ich spekuliere nur, aber ich denke, sie wollten, dass die Zugriffsebenen streng aufeinander abgestimmt sind: privat - "Paket" - geschützt - öffentlich. Sie wollten keine Hierarchie, in der einige Felder für das Paket, jedoch nicht für Unterklassen verfügbar sind, andere für Unterklassen, jedoch nicht für das Paket, und einige für beide.
Meiner bescheidenen Meinung nach hätten sie den umgekehrten Weg gehen müssen: Gesagt, dass protected nur für die Klasse und die Unterklassen sichtbar ist und dass das Paket für die Klasse, die Unterklassen und das Paket sichtbar ist.
Ich habe oft Daten in einer Klasse, auf die Unterklassen zugreifen können müssen, nicht aber der Rest des Pakets. Es fällt mir schwer, mir einen Fall vorzustellen, in dem das Gegenteil der Fall war. Es gab einige seltene Fälle, in denen ich ein Bündel miteinander verbundener Klassen hatte, die Daten gemeinsam nutzen müssen, die diese Daten jedoch vor dem Zugriff außerhalb des Bündels schützen sollten. Also okay, packen Sie sie in ein Paket usw. Aber ich hatte noch nie einen Fall, in dem das Paket Daten freigeben soll, aber ich möchte, dass es nicht in Unterklassen unterteilt wird. Okay, ich kann mir die Situation vorstellen. Ich nehme an, wenn dieses Paket Teil einer Bibliothek ist, die möglicherweise um Klassen erweitert wird, von denen ich nichts weiß, aus den gleichen Gründen, aus denen ich Daten in einer Klasse privat machen würde. Es ist jedoch weitaus üblicher, Daten nur für die Klasse und ihre Kinder verfügbar zu machen.
Es gibt viele Dinge, die ich zwischen mir und meinen Kindern geheim halte und die wir nicht mit den Nachbarn teilen. Es gibt sehr wenig, was ich privat zwischen mir und den Nachbarn halte und nicht mit meinen Kindern teile. :-)
quelle
Ein gutes Beispiel, das einem sofort in den Sinn kommt, sind Utility-Klassen, die häufig im Paket verwendet werden, aber keinen öffentlichen Zugriff benötigen (Klassen zum Laden von Images von der Festplatte hinter den Kulissen, Erstellen / Zerstören von Handles usw.) .) Anstatt alles [Javas Äquivalent
friend access modifier or idiom
inC++
] von jeder anderen Klasse zu machen, ist alles automatisch verfügbar.quelle
Die Anwendungsfälle für den Zugriffsmodifikator protected / package ähneln denen für die Zugriffsmodifikatoren friend in C ++.
Ein Anwendungsfall ist die Implementierung des Memento-Musters .
Das Memento-Objekt muss auf den internen Zustand eines Objekts zugreifen, um es zu halten, damit es als Prüfpunkt für das Rückgängigmachen von Vorgängen dient.
Das Deklarieren der Klasse im selben Paket ist eine der Möglichkeiten, um das Memento-Muster zu erzielen, da Java keinen Zugriffsmodifikator "friend" hat .
quelle
Symmetrie?
Es ist selten, dass ein solcher Zugriff erforderlich ist, weshalb der Standardzugriff so selten verwendet wird. Aber manchmal möchten Frameworks es für generierten Code, bei dem Wrapper-Klassen in demselben Paket abgelegt werden, das direkt mit Ihren Klassen interagiert, und aus Leistungsgründen an Mitglieder anstatt an Accessoren gehen. Denken Sie an GWT.
quelle
Die Verkapselungshierarchie von Java ist gut definiert:
Klasse -> Paket -> Vererbung
"Geschützt" ist nur eine schwächere Form der Vertraulichkeit als die von den Java-Designern festgelegten Paketstandards. Der Zugriff auf Paketstandardelemente ist auf eine Teilmenge der Entitäten beschränkt, die auf geschützte Elemente zugreifen dürfen.
Aus mathematischer und Implementierungssicht ist es sehr sinnvoll, Ihre Entitätenmengen so zu gestalten, dass sie auf verschachtelte Objekte zugreifen können. (Sie konnten Ihren Paketzugriffssatz nicht in Ihrem geschützten Zugriffssatz verschachteln, da Klassen von anderen Paketen erben dürfen.)
Aus konzeptioneller Sicht ist es sinnvoll, in java.util etwas zu haben, das "freundlicher" mit einer anderen Klasse im Paket ist als etwas in com.example.foo.bar, das diese Klasse unterordnet. Im ersteren Fall werden die Klassen wahrscheinlich vom selben Autor oder zumindest von Programmierern derselben Organisation geschrieben.
quelle