Public vs Private Members
Part of the Object Oriented Programming section of Coddy's Dart journey — lesson 30 of 110.
Encapsulation is one of the core principles of object-oriented programming. It's about controlling access to a class's internal data, deciding what should be visible to the outside world and what should remain hidden.
In Dart, class members (fields and methods) are public by default. This means any code can access them directly:
class BankAccount {
String owner;
double balance;
BankAccount(this.owner, this.balance);
}
var account = BankAccount('Alice', 1000);
account.balance = -500; // Anyone can modify this directly!This is problematic. Nothing prevents setting an invalid balance.
To protect internal data, Dart uses private members. A member becomes private when its name starts with an underscore _:
class BankAccount {
String owner;
double _balance; // Private - starts with underscore
BankAccount(this.owner, this._balance);
double get balance => _balance; // Controlled access
}Now _balance cannot be accessed directly from outside the library where the class is defined. External code must use the public getter instead. This lets you control how data is read and modified, ensuring your objects always remain in a valid state.
Challenge
EasyLet's build a simple password manager that demonstrates the difference between public and private members. You'll see how the underscore prefix protects sensitive data from being accessed directly from outside the class's library.
You'll create two files to organize your code:
credential.dart: Define aCredentialclass that stores login information for a website. The class should have:- A public
String website- it's fine for anyone to see which website this is for - A public
String username- the username can be visible - A private
String _password- the actual password must be protected - A constructor that takes all three values
- A public getter
passwordthat returns the private_password(controlled access) - A method
getMaskedPassword()that returns the password with all characters replaced by asterisks*(same length as the actual password) - A method
displayCredential()that prints the credential information safely (showing the masked password, not the real one)
- A public
main.dart: Import your credential class and demonstrate how encapsulation protects the password:- Create a credential for website
'github.com', username'dev_user', and password'secret123' - Create another credential for website
'email.com', username'john_doe', and password'myP@ss' - For each credential, call
displayCredential(), then printActual password length: [length]using the public getter to access the password's length
- Create a credential for website
The displayCredential() method should print in this format:
--- Credential ---
Website: [website]
Username: [username]
Password: [maskedPassword]Expected output:
--- Credential ---
Website: github.com
Username: dev_user
Password: *********
Actual password length: 9
--- Credential ---
Website: email.com
Username: john_doe
Password: ******
Actual password length: 6Cheat sheet
Encapsulation controls access to a class's internal data by deciding what should be visible and what should remain hidden.
In Dart, class members are public by default:
class BankAccount {
String owner;
double balance; // Public - can be accessed directly
BankAccount(this.owner, this.balance);
}
var account = BankAccount('Alice', 1000);
account.balance = -500; // Direct modification allowedTo protect internal data, use private members by prefixing the name with an underscore _:
class BankAccount {
String owner;
double _balance; // Private - starts with underscore
BankAccount(this.owner, this._balance);
double get balance => _balance; // Controlled access via getter
}Private members cannot be accessed directly from outside the library where the class is defined. Use public getters and methods to provide controlled access to private data, ensuring objects remain in a valid state.
Try it yourself
import 'credential.dart';
void main() {
// TODO: Create a credential for github.com
// website: 'github.com', username: 'dev_user', password: 'secret123'
// TODO: Call displayCredential() on the first credential
// TODO: Print the actual password length using the public getter
// Format: "Actual password length: [length]"
// TODO: Create a credential for email.com
// website: 'email.com', username: 'john_doe', password: 'myP@ss'
// TODO: Call displayCredential() on the second credential
// TODO: Print the actual password length using the public getter
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesLibraries & ImportsIntroduction to OOPClasses vs ObjectsThe this KeywordMethodsInstance VariablesConstructor BasicsRecap - Simple Calculator4Null Safety
Intro to Null SafetyNullable vs Non-NullableThe ? and ! OperatorsLate Keyword & Null SafetyNull-Aware OperatorsNull Safety in ClassesRecap - User Profile System7Abstract Classes & Interfaces
Abstract ClassesAbstract MethodsInterfaces in DartImplicit InterfacesImplementing vs ExtendingMultiple InterfacesRecap - Shape Calculator10Collections & Generics
List, Set, Map OverviewType-Safe CollectionsGeneric ClassesGeneric MethodsGeneric ConstraintsIterable & IteratorRecap - Generic Storage13Advanced OOP Concepts
Composition vs InheritanceExtension MethodsCallable ClassesSealed Classes (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums with Methods16Project: Library Management
Project OverviewBook and User Classes2Constructors in Dart
Default ConstructorNamed ConstructorsInitializer ListsConstant ConstructorsFactory ConstructorsRedirecting ConstructorsRecap - Shape Builder5Encapsulation
Public vs Private MembersThe _ Prefix ConventionLibrary-Level PrivacyGetters & Setters DepthInformation HidingRecap - Student Records8Mixins
Introduction to MixinsCreating MixinsUsing Multiple Mixinson Keyword in MixinsMixin vs InheritanceMixin vs InterfaceRecap - Animal System11Special Methods
toString() OverridehashCode & == OverrideComparable Interfacecall() MethodnoSuchMethod OverrideRecap - Custom Collection14Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternObserver PatternStrategy Pattern3Class Properties
Instance vs Static MembersFinal & Const FieldsLate VariablesStatic Methods & FieldsGetters and SettersRecap - Bank Account Manager6Inheritance
Basic InheritanceThe super KeywordMethod OverridingThe @override AnnotationThe final Class KeywordConstructors & InheritanceRecap - Employee Hierarchy9Polymorphism
Polymorphism BasicsPolymorphism via InterfacesRuntime Type CheckingThe is & as OperatorsCovariant KeywordRecap - Payment Processor