← Назад к вопросам

Какие знаешь модификаторы доступа в Dart?

1.0 Junior🔥 141 комментариев
#Dart

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Какие знаешь модификаторы доступа в 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Одна инициализацияНеизменяемые значения
constCompile-time constantКонстанты и оптимизация
lateЛенивая инициализацияStatefulWidget, сложная инициализация
requiredОбязательный параметрЯвная необходимость

Лучшие практики

  1. Делайте поля приватными по умолчанию — используйте _field
  2. Предоставляйте публичные getters для чтения данных
  3. Используйте setters для валидации — не просто присваивайте значение
  4. Помечайте const когда возможно — лучшая оптимизация
  5. Используйте final для неизменяемых данных — безопаснее
  6. Используйте 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 — это мощный инструмент для создания надёжного, безопасного и поддерживаемого кода.

Какие знаешь модификаторы доступа в Dart? | PrepBro