Sichtbarkeit auf Library-Ebene
Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy — Lektion 32 von 110.
In Dart wird die Privatsphäre auf der Library-Ebene erzwungen, nicht auf der Klassenebene. Dies ist ein wesentlicher Unterschied zu Sprachen wie Java oder C++. Eine Library in Dart ist normalerweise eine einzelne Datei oder mehrere Dateien, die mit part-Direktiven verbunden sind.
Private Member (solche, die mit _ beginnen) sind überall innerhalb derselben Bibliothek zugänglich, sogar von anderen Klassen aus:
// Beide Klassen in derselben Datei (dieselbe Bibliothek)
class Engine {
int _horsepower = 200; // Privat für diese Bibliothek
}
class Car {
void showPower(Engine engine) {
print(engine._horsepower); // Zugänglich! Dieselbe Bibliothek
}
}Wenn Sie jedoch eine Klasse aus einer anderen Datei importieren, werden ihre privaten Member wirklich verborgen:
// Datei: engine.dart
class Engine {
int _horsepower = 200;
int get power => _horsepower;
}
// Datei: main.dart
import 'engine.dart';
void main() {
var engine = Engine();
// print(engine._horsepower); // Fehler! Nicht zugänglich
print(engine.power); // Funktioniert - Verwendung des öffentlichen Getters
}Diese Sichtbarkeit auf Bibliotheksebene bedeutet, dass Klassen in derselben Datei eng zusammenarbeiten können, während Implementierungsdetails vor externem Code verborgen bleiben. Es ist eine bewusste Designentscheidung, die dazu anregt, zusammengehörige Klassen in derselben Bibliothek zu organisieren.
Aufgabe
EinfachLassen Sie uns ein Team-Zusammenarbeitssystem erstellen, das zeigt, wie der Datenschutz auf Bibliotheksebene in Dart funktioniert. Sie werden sehen, wie Klassen in derselben Datei auf die privaten Member der jeweils anderen zugreifen können, während Code in separaten Dateien dies nicht kann.
Sie werden Ihren Code in zwei Dateien organisieren:
team.dart: Diese Datei enthält zwei Klassen, die in derselben Bibliothek eng zusammenarbeiten:- Eine
Member-Klasse mit einem öffentlichenString nameund einem privatenint _performanceScore, der mit50initialisiert wird. Fügen Sie einen Konstruktor hinzu, der den Namen entgegennimmt, und einen öffentlichen GetterperformanceScore, der den privaten Score zurückgibt. - Eine
TeamLead-Klasse in derselben Datei, die direkt auf das private Feld vonMemberzugreifen kann (da sie sich in derselben Bibliothek befinden). Diese Klasse sollte einen öffentlichenString namehaben, einen Konstruktor, der den Namen entgegennimmt, und eine MethodeevaluateMember(Member member), die direkt aufmember._performanceScorezugreift,10dazu addiert und[leadName] boosted [memberName]'s score to [newScore]ausgibt.
- Eine
main.dart: Importieren Sie Ihre Team-Datei und demonstrieren Sie den Unterschied beim Zugriff:- Erstellen Sie ein
Membernamens'Alice' - Erstellen Sie einen
TeamLeadnamens'Bob' - Geben Sie
Initial score: [score]unter Verwendung des öffentlichen Getters für Alice aus - Lassen Sie Bob Alice mit
evaluateMemberbewerten - Geben Sie
Updated score: [score]unter Verwendung des öffentlichen Getters aus - Geben Sie
Direct access from main: Not allowedaus (dies erinnert uns daran, dassmain.dartnicht direkt auf_performanceScorezugreifen kann, da es sich in einer anderen Bibliothek befindet)
- Erstellen Sie ein
Die entscheidende Erkenntnis hierbei ist, dass TeamLead den privaten _performanceScore von Member direkt lesen und ändern kann, da beide Klassen in derselben Datei (derselben Bibliothek) liegen. Code in main.dart muss jedoch den öffentlichen Getter verwenden, da er sich in einer anderen Bibliothek befindet.
Erwartete Ausgabe:
Initial score: 50
Bob boosted Alice's score to 60
Updated score: 60
Direct access from main: Not allowedSpickzettel
In Dart wird der Zugriffsschutz auf der Library-Ebene erzwungen, nicht auf der Klassenebene. Eine Library ist normalerweise eine einzelne Datei oder mehrere Dateien, die mit part-Direktiven verbunden sind.
Private Member beginnen mit einem Unterstrich (_) und sind überall innerhalb derselben Library zugänglich, sogar von anderen Klassen aus:
// Beide Klassen in derselben Datei (gleiche Library)
class Engine {
int _horsepower = 200; // Privat für diese Library
}
class Car {
void showPower(Engine engine) {
print(engine._horsepower); // Zugänglich! Gleiche Library
}
}Wenn Sie eine Klasse aus einer anderen Datei importieren, werden ihre privaten Member verborgen:
// file: engine.dart
class Engine {
int _horsepower = 200;
int get power => _horsepower;
}
// file: main.dart
import 'engine.dart';
void main() {
var engine = Engine();
// print(engine._horsepower); // Fehler! Nicht zugänglich
print(engine.power); // Funktioniert - Verwendung des öffentlichen Getters
}Dieses Design fördert die Organisation zusammengehöriger Klassen in derselben Library, sodass sie eng zusammenarbeiten können, während Implementierungsdetails vor externem Code verborgen bleiben.
Probier es selbst
import 'team.dart';
void main() {
// TODO: Erstelle ein Member namens 'Alice'
// TODO: Erstelle einen TeamLead namens 'Bob'
// TODO: Gib "Initial score: [score]" unter Verwendung des öffentlichen Getters für Alice aus
// TODO: Lass Bob Alice mit evaluateMember bewerten
// TODO: Gib "Updated score: [score]" unter Verwendung des öffentlichen Getters aus
// TODO: Gib "Direct access from main: Not allowed" aus
// Note: Wir können hier nicht auf alice._performanceScore zugreifen, da
// main.dart sich in einer anderen Library als team.dart befindet
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienBibliotheken & ImportsEinführung in die OOPKlassen vs. ObjekteDas this-SchlüsselwortMethodenInstanzvariablenKonstruktor-GrundlagenWiederholung – Einfacher Taschenrechner4Null-Sicherheit
Einführung in Null-SicherheitNullable vs. Non-NullableDie ? und ! OperatorenLate-Schlüsselwort & Null-SicherheitNull-aware OperatorenNull-Sicherheit in KlassenZusammenfassung – Benutzerprofil-System7Abstrakte Klassen & Interfaces
Abstrakte KlassenAbstrakte MethodenInterfaces in DartImplizite InterfacesImplementieren vs. ErweiternMehrfache InterfacesRückblick – Shape Calculator10Collections & Generics
Überblick über List, Set und MapTypsichere CollectionsGenerische KlassenGenerische MethodenGenerische ConstraintsIterable & IteratorZusammenfassung – Generische Speicherung13Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungExtension MethodsCallable ClassesSealed Classes (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums mit Methoden16Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen2Konstruktoren in Dart
Standard-KonstruktorBenannte KonstruktorenInitialisierungslistenKonstante KonstruktorenFactory-KonstruktorenWeiterleitende KonstruktorenZusammenfassung – Shape Builder5Kapselung
Öffentliche vs. private MemberDie _ Präfix-KonventionSichtbarkeit auf Library-EbeneGetter & Setter im DetailInformation HidingRückblick – Schülerdatensätze8Mixins
Einführung in MixinsMixins erstellenMehrere Mixins verwendenDas on-Schlüsselwort in MixinsMixin vs. VererbungMixin vs. InterfaceZusammenfassung - Tiersystem11Spezielle Methoden
toString() überschreibenhashCode & == überschreibenComparable-Interfacecall()-MethodenoSuchMethod überschreibenZusammenfassung – Eigene Collection14Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster3Klasseneigenschaften
Instanz- vs. statische MemberFinal & Const FelderLate-VariablenStatische Methoden & FelderGetter und SetterZusammenfassung – Bankkonto-Manager6Vererbung
Grundlagen der VererbungDas super-SchlüsselwortMethoden überschreibenDie @override-AnnotationDas final-Klassen-SchlüsselwortKonstruktoren & VererbungRückblick – Mitarbeiter-Hierarchie9Polymorphismus
Polymorphismus-GrundlagenPolymorphismus über InterfacesTypprüfung zur LaufzeitDie is & as OperatorenDas covariant SchlüsselwortZusammenfassung – Payment Processor