Answer
Overview
Getters and Setters are special methods that provide controlled access to class properties. They allow you to read (get) and write (set) private fields with custom logic.
Getter
Definition: A method that retrieves (reads) the value of a property.
Syntax
dartclass Person { String _name = 'Alice'; // Private field // Getter - read-only access String get name => _name; // Getter with logic String get greeting => 'Hello, $_name!'; } void main() { final person = Person(); print(person.name); // Alice (calls getter) print(person.greeting); // Hello, Alice! }
Key Features
- Read-only access to private fields
- Can include custom logic
- Called like a property (no parentheses)
- Cannot take parameters
- Must return a value
Setter
Definition: A method that updates (writes) the value of a property with validation or side effects.
Syntax
dartclass Person { String _name = 'Alice'; // Getter String get name => _name; // Setter - controlled write access set name(String value) { if (value.isNotEmpty) { _name = value; } } } void main() { final person = Person(); print(person.name); // Alice person.name = 'Bob'; // Calls setter print(person.name); // Bob person.name = ''; // Invalid - setter ignores print(person.name); // Bob (unchanged) }
Key Features
- Write access with validation
- Can include business logic
- Called like a property assignment
- Takes exactly one parameter
- No return value
Getter vs Setter Comparison
| Feature | Getter | Setter |
|---|---|---|
| Purpose | Read property value | Write property value |
| Syntax | text | text |
| Parameters | None | Exactly one |
| Return type | Any type | void (no return) |
| Access | Read-only | Write-only |
| Usage | text | text |
| Can validate | No | Yes |
Real-World Examples
Example 1: Validation
dartclass User { String _email = ''; int _age = 0; // Getter for email String get email => _email; // Setter with validation set email(String value) { if (value.contains('@')) { _email = value; } else { throw ArgumentError('Invalid email format'); } } // Getter for age int get age => _age; // Setter with validation set age(int value) { if (value >= 0 && value <= 150) { _age = value; } } } void main() { final user = User(); user.email = 'test@example.com'; // ✅ Valid print(user.email); // test@example.com // user.email = 'invalid'; // ❌ Throws ArgumentError user.age = 25; // ✅ Valid print(user.age); // 25 user.age = 200; // ❌ Invalid - ignored print(user.age); // 25 (unchanged) }
Example 2: Computed Properties
dartclass Rectangle { double width; double height; Rectangle(this.width, this.height); // Computed getter (no backing field) double get area => width * height; double get perimeter => 2 * (width + height); // Setter for area updates dimensions proportionally set area(double newArea) { double scaleFactor = sqrt(newArea / area); width *= scaleFactor; height *= scaleFactor; } } void main() { final rect = Rectangle(5, 10); print(rect.area); // 50.0 (computed) print(rect.perimeter); // 30.0 (computed) rect.area = 100; // Set new area print(rect.width); // ~7.07 print(rect.height); // ~14.14 }
Example 3: Side Effects
dartclass Counter { int _count = 0; int get count => _count; set count(int value) { _count = value; print('Count updated to $_count'); // Side effect: logging _notifyListeners(); // Side effect: notify observers } void _notifyListeners() { // Notify UI or listeners } }
Example 4: Flutter Widget State
dartclass SliderWidget extends StatefulWidget { _SliderWidgetState createState() => _SliderWidgetState(); } class _SliderWidgetState extends State<SliderWidget> { double _sliderValue = 0.5; // Getter double get sliderValue => _sliderValue; // Setter with setState set sliderValue(double value) { setState(() { _sliderValue = value.clamp(0.0, 1.0); // Validate range }); } Widget build(BuildContext context) { return Slider( value: sliderValue, onChanged: (value) { sliderValue = value; // Calls setter }, ); } }
Read-Only vs Write-Only Properties
Read-Only (Getter Only)
dartclass Circle { final double radius; Circle(this.radius); // Read-only computed property double get area => 3.14159 * radius * radius; double get circumference => 2 * 3.14159 * radius; } void main() { final circle = Circle(5); print(circle.area); // 78.54 (can read) // circle.area = 100; // ❌ Error - no setter }
Write-Only (Setter Only)
dartclass Logger { // No getter - write-only set logMessage(String message) { print('[LOG] $message'); // Could write to file, send to server, etc. } } void main() { final logger = Logger(); logger.logMessage = 'User logged in'; // ✅ Can write // print(logger.logMessage); // ❌ Error - no getter }
Getter/Setter vs Public Fields
Public Field (No Control)
dartclass User { String name; // Anyone can read/write User(this.name); } void main() { final user = User('Alice'); user.name = ''; // ❌ No validation - allows empty name }
Getter/Setter (Controlled)
dartclass User { String _name; User(this._name); String get name => _name; set name(String value) { if (value.isNotEmpty) { // ✅ Validation _name = value; } } } void main() { final user = User('Alice'); user.name = ''; // Ignored - validation prevents empty name }
Common Use Cases
| Use Case | Example |
|---|---|
| Validation | Email format, age range |
| Computed values | Area from width/height |
| Logging | Track property changes |
| State updates | Trigger text |
| Data transformation | Convert units, format strings |
| Encapsulation | Hide internal implementation |
Best Practices
✅ DO:
dart// Use getters for computed properties double get fullName => '$firstName $lastName'; // Use setters for validation set age(int value) { if (value >= 0) _age = value; } // Use private fields with getters/setters String _email; String get email => _email; set email(String value) { _email = value; }
❌ DON'T:
dart// Don't use getters for expensive operations double get calculateComplexValue { // ❌ Bad - expensive computation for (int i = 0; i < 1000000; i++) { ... } } // Don't use setters with side effects users don't expect set name(String value) { _name = value; saveToDatabase(); // ❌ Unexpected side effect } // Don't make everything private String _publicData; // ❌ If no validation needed, use public field
Getter/Setter in Flutter State Management
GetX
dartclass CounterController extends GetxController { int _count = 0; int get count => _count; set count(int value) { _count = value; update(); // Notify listeners } }
BLoC
dartclass CounterBloc extends Bloc<CounterEvent, CounterState> { int _count = 0; int get count => _count; // Getter // No setter - use events instead void increment() { _count++; emit(CounterState(_count)); } }
Key Takeaways
Getter: Read property with
(no parentheses)textobj.property
Setter: Write property with
textobj.property = value
Use when: You need validation, computed values, or controlled access
Avoid when: Simple public fields suffice (no validation needed)