Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Какие знаешь модификаторы доступа в Dart?
Dart имеет минималистичный набор модификаторов доступа по сравнению с другими языками ООП, но это не снижает мощь и гибкость языка. Рассмотрю все варианты.
Публичные члены (Public)
По умолчанию все члены класса публичны:
class User {
String name = 'John'; // Публичное свойство
void printName() { // Публичный метод
print('Name: $name');
}
}
final user = User();
print(user.name); // Доступно
user.printName(); // Доступно
Приватные члены (Private)
Обозначаются подчеркиванием в начале имени (_). Доступны только внутри библиотеки (файла):
class BankAccount {
double _balance = 1000; // Приватное свойство
void _updateLog(String action) { // Приватный метод
print('[LOG] $action');
}
void withdraw(double amount) {
if (amount <= _balance) {
_balance -= amount;
_updateLog('Withdraw $amount'); // Доступ внутри класса
}
}
double getBalance() => _balance; // Публичный getter для доступа
}
final account = BankAccount();
account.withdraw(100); // Публичный метод
// account._balance = -500; // ОШИБКА! Приватное
print(account.getBalance()); // Правильно
ВАЖНО: Приватность в Dart работает на уровне библиотеки (файла), а не класса:
// file_a.dart
class A {
int _privateField = 5;
}
// file_b.dart
import 'file_a.dart';
class B {
void accessPrivate() {
final a = A();
// a._privateField; // ОШИБКА! Приватное на уровне библиотеки
}
}
// Но в ОДНОМ файле это работает:
class C {
void test() {
final a = A();
print(a._privateField); // OK! Одна библиотека
}
}
Getters и Setters
Делают управление доступом более гибким:
class Rectangle {
double _width;
double _height;
Rectangle(this._width, this._height);
double get width => _width; // Getter
set width(double value) { // Setter
if (value <= 0) throw ArgumentError('Width must be positive');
_width = value;
}
double get height => _height;
set height(double value) {
if (value <= 0) throw ArgumentError('Height must be positive');
_height = value;
}
double get area => _width * _height; // Вычисляемое свойство
}
final rect = Rectangle(10, 5);
print(rect.width); // Getter
rect.width = 15; // Setter с валидацией
print(rect.area); // 75 (вычисляемое свойство)
// rect.width = -5; // ОШИБКА! Валидация в setter
Финальные члены (Final)
Можно установить один раз, после чего нельзя изменять:
class User {
final String id; // Должен быть инициализирован
final String name;
User({required this.id, required this.name});
}
final user = User(id: '1', name: 'John');
// user.id = '2'; // ОШИБКА! final
// user.name = 'Jane'; // ОШИБКА! final
Разница между final и const:
class Point {
final int x = 5; // final — значение устанавливается в runtime
final int y = 10;
}
class ConstPoint {
const int x = 5; // const — значение известно в compile time
}
// final может быть runtime значением
final dynamicValue = DateTime.now(); // OK
// const dynamicValue = DateTime.now(); // ОШИБКА!
Const
Обозначает, что значение константно на уровне компилятора:
const int MAX_USERS = 100; // Глобальная константа
const List<int> FIBONACCI = [1, 1, 2, 3, 5, 8];
class Config {
static const String APP_NAME = 'MyApp';
static const int VERSION = 1;
}
// Объекты могут быть const
class Point {
final int x;
final int y;
const Point(this.x, this.y); // const конструктор
}
const point1 = Point(1, 2);
const point2 = Point(1, 2);
print(identical(point1, point2)); // true! Один объект в памяти
Late (Ленивая инициализация)
Позволяет объявить переменную без немедленной инициализации:
class User {
late String _password; // Объявлено, но не инициализировано
void setPassword(String pwd) {
_password = pwd; // Инициализация
}
String getPassword() => _password; // Доступ
}
final user = User();
// print(user.getPassword()); // ОШИБКА! LateInitializationError
user.setPassword('secret');
print(user.getPassword()); // secret
Late в StatefulWidget:
class MyHomePage extends StatefulWidget {
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late TextEditingController _controller; // Инициализируется в initState
@override
void initState() {
super.initState();
_controller = TextEditingController(); // Late инициализация
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return TextField(controller: _controller);
}
}
Требуемые параметры (Required)
Обозначает, что параметр обязательный:
class User {
final String name;
final int? age; // nullable - опциональный
User({required this.name, this.age}); // name обязателен
}
final user1 = User(name: 'John'); // OK
final user2 = User(name: 'Jane', age: 25); // OK
// final user3 = User(age: 30); // ОШИБКА! name требуется
Резюме модификаторов доступа
| Модификатор | Уровень доступа | Использование |
|---|---|---|
| Публичный (по умолчанию) | Вся библиотека | Для публичного API |
| _ (приватный) | Только этот файл | Для внутренней логики |
| final | Одна инициализация | Неизменяемые значения |
| const | Compile-time constant | Константы и оптимизация |
| late | Ленивая инициализация | StatefulWidget, сложная инициализация |
| required | Обязательный параметр | Явная необходимость |
Лучшие практики
- Делайте поля приватными по умолчанию — используйте
_field - Предоставляйте публичные getters для чтения данных
- Используйте setters для валидации — не просто присваивайте значение
- Помечайте const когда возможно — лучшая оптимизация
- Используйте final для неизменяемых данных — безопаснее
- Используйте required для обязательных параметров — явнее и безопаснее
// Правильно
class Product {
final String _id;
final String _name;
double _price;
Product({required String id, required String name, required double price})
: _id = id, _name = name, _price = price;
String get id => _id;
String get name => _name;
double get price => _price;
set price(double newPrice) {
if (newPrice < 0) throw ArgumentError('Price cannot be negative');
_price = newPrice;
}
}
Модификаторы доступа в Dart — это мощный инструмент для создания надёжного, безопасного и поддерживаемого кода.