Menu
Coddy logo textTech

Приватность на уровне библиотек

Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy — урок 32 из 110.

В Dart приватность обеспечивается на уровне библиотеки, а не на уровне класса. Это ключевое отличие от таких языков, как Java или C++. Библиотека в Dart — это обычно один файл или несколько файлов, соединенных директивами part.

Приватные члены (начинающиеся с _) доступны в любом месте той же библиотеки, даже из других классов:

// Оба класса в одном файле (одна библиотека)
class Engine {
  int _horsepower = 200;  // Приватно для этой библиотеки
}

class Car {
  void showPower(Engine engine) {
    print(engine._horsepower);  // Доступно! Та же библиотека
  }
}

Однако, когда вы импортируете класс из другого файла, его приватные члены становятся по-настоящему скрытыми:

// файл: engine.dart
class Engine {
  int _horsepower = 200;
  int get power => _horsepower;
}

// файл: main.dart
import 'engine.dart';

void main() {
  var engine = Engine();
  // print(engine._horsepower);  // Ошибка! Нет доступа
  print(engine.power);           // Работает — используется публичный геттер
}

Эта приватность на уровне библиотеки означает, что классы в одном и том же файле могут тесно взаимодействовать, при этом скрывая детали реализации от внешнего кода. Это осознанное проектное решение, которое стимулирует организацию связанных классов вместе в одной библиотеке.

challenge icon

Задание

Легко

Давайте создадим систему командного взаимодействия, которая демонстрирует, как работает приватность на уровне библиотеки в Dart. Вы увидите, как классы в одном и том же файле могут получать доступ к приватным членам друг друга, в то время как код в отдельных файлах этого сделать не может.

Вы организуете свой код в двух файлах:

  • team.dart: Этот файл будет содержать два класса, которые тесно взаимодействуют в одной библиотеке:
    • Класс Member с публичным полем String name и приватным полем int _performanceScore, инициализированным значением 50. Добавьте конструктор, принимающий имя, и публичный геттер performanceScore, который возвращает приватный показатель.
    • Класс TeamLead в том же файле, который может напрямую обращаться к приватному полю Member (поскольку они находятся в одной библиотеке). Этот класс должен иметь публичное поле String name, конструктор, принимающий имя, и метод evaluateMember(Member member), который напрямую обращается к member._performanceScore, добавляет к нему 10 и выводит [leadName] boosted [memberName]'s score to [newScore].
  • main.dart: Импортируйте файл вашей команды и продемонстрируйте разницу в доступе:
    • Создайте Member с именем 'Alice'
    • Создайте TeamLead с именем 'Bob'
    • Выведите Initial score: [score], используя публичный геттер у Alice
    • Пусть Bob оценит Alice с помощью evaluateMember
    • Выведите Updated score: [score], используя публичный геттер
    • Выведите Direct access from main: Not allowed (это напоминает нам о том, что main.dart не может напрямую обращаться к _performanceScore, так как находится в другой библиотеке)

Ключевой момент здесь заключается в том, что TeamLead может напрямую читать и изменять приватное поле _performanceScore класса Member, потому что оба класса находятся в одном файле (одной библиотеке). Однако код в main.dart должен использовать публичный геттер, так как он находится в другой библиотеке.

Ожидаемый вывод:

Initial score: 50
Bob boosted Alice's score to 60
Updated score: 60
Direct access from main: Not allowed

Шпаргалка

В Dart инкапсуляция (приватность) обеспечивается на уровне библиотеки, а не на уровне класса. Библиотека — это обычно один файл или несколько файлов, соединенных директивами part.

Приватные члены начинаются с символа подчеркивания (_) и доступны в любом месте той же библиотеки, даже из других классов:

// Оба класса в одном файле (одна библиотека)
class Engine {
  int _horsepower = 200;  // Приватно для этой библиотеки
}

class Car {
  void showPower(Engine engine) {
    print(engine._horsepower);  // Доступно! Та же библиотека
  }
}

Когда вы импортируете класс из другого файла, его приватные члены становятся скрытыми:

// файл: engine.dart
class Engine {
  int _horsepower = 200;
  int get power => _horsepower;
}

// файл: main.dart
import 'engine.dart';

void main() {
  var engine = Engine();
  // print(engine._horsepower);  // Ошибка! Недоступно
  print(engine.power);           // Работает — используется публичный геттер
}

Такой подход поощряет группировку связанных классов в одной библиотеке, позволяя им тесно взаимодействовать, скрывая при этом детали реализации от внешнего кода.

Попробуйте сами

import 'team.dart';

void main() {
  // TODO: Создайте Member с именем 'Alice'

  // TODO: Создайте TeamLead с именем 'Bob'

  // TODO: Выведите "Initial score: [score]", используя публичный getter для Alice

  // TODO: Пусть Bob оценит Alice, используя evaluateMember

  // TODO: Выведите "Updated score: [score]", используя публичный getter

  // TODO: Выведите "Direct access from main: Not allowed"
  // Note: Мы не можем получить доступ к alice._performanceScore здесь, потому что
  // main.dart находится в другой библиотеке, чем team.dart
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование