Menu
Coddy logo textTech

Публичные и приватные члены

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

Инкапсуляция — один из основных принципов объектно-ориентированного программирования. Она заключается в управлении доступом к внутренним данным класса, определении того, что должно быть видимым для внешнего мира, а что должно оставаться скрытым.

В Dart члены класса (поля и методы) являются публичными по умолчанию. Это означает, что любой код может обращаться к ним напрямую:

class BankAccount {
  String owner;
  double balance;
  
  BankAccount(this.owner, this.balance);
}

var account = BankAccount('Alice', 1000);
account.balance = -500;  // Кто угодно может изменить это напрямую!

Это создает проблему. Ничто не мешает установить недопустимый баланс.

Для защиты внутренних данных Dart использует приватные члены. Член становится приватным, когда его имя начинается с символа подчеркивания _:

class BankAccount {
  String owner;
  double _balance;  // Приватное - начинается с подчеркивания
  
  BankAccount(this.owner, this._balance);
  
  double get balance => _balance;  // Контролируемый доступ
}

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

challenge icon

Задание

Легко

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

Вы создадите два файла для организации вашего кода:

  • credential.dart: Определите класс Credential, который хранит информацию для входа на веб-сайт. Класс должен иметь:
    • Публичное поле String website — любой может видеть, для какого сайта это предназначено
    • Публичное поле String username — имя пользователя может быть видимым
    • Приватное поле String _password — сам пароль должен быть защищен
    • Конструктор, который принимает все три значения
    • Публичный геттер password, который возвращает приватное поле _password (контролируемый доступ)
    • Метод getMaskedPassword(), который возвращает пароль, где все символы заменены на звездочки * (той же длины, что и настоящий пароль)
    • Метод displayCredential(), который безопасно выводит информацию об учетных данных (показывая замаскированный пароль, а не настоящий)
  • main.dart: Импортируйте ваш класс учетных данных и продемонстрируйте, как инкапсуляция защищает пароль:
    • Создайте учетную запись для веб-сайта 'github.com', имя пользователя 'dev_user' и пароль 'secret123'
    • Создайте еще одну учетную запись для веб-сайта 'email.com', имя пользователя 'john_doe' и пароль 'myP@ss'
    • Для каждой учетной записи вызовите displayCredential(), затем выведите Actual password length: [length], используя публичный геттер для доступа к длине пароля

Метод displayCredential() должен выводить данные в следующем формате:

--- Credential ---
Website: [website]
Username: [username]
Password: [maskedPassword]

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

--- Credential ---
Website: github.com
Username: dev_user
Password: *********
Actual password length: 9
--- Credential ---
Website: email.com
Username: john_doe
Password: ******
Actual password length: 6

Шпаргалка

Инкапсуляция управляет доступом к внутренним данным класса, определяя, что должно быть видимым, а что должно оставаться скрытым.

В Dart члены класса являются публичными по умолчанию:

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 allowed

Чтобы защитить внутренние данные, используйте приватные члены, добавляя перед именем символ подчеркивания _:

class BankAccount {
  String owner;
  double _balance;  // Private - starts with underscore
  
  BankAccount(this.owner, this._balance);
  
  double get balance => _balance;  // Controlled access via getter
}

К приватным членам нельзя получить прямой доступ извне библиотеки, в которой определен класс. Используйте публичные геттеры и методы для обеспечения контролируемого доступа к приватным данным, гарантируя, что объекты остаются в валидном состоянии.

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

import 'credential.dart';

void main() {
  // TODO: Создайте учетные данные для github.com
  // website: 'github.com', username: 'dev_user', password: 'secret123'
  
  // TODO: Вызовите displayCredential() для первых учетных данных
  
  // TODO: Выведите фактическую длину пароля, используя публичный геттер
  // Format: "Actual password length: [length]"
  
  // TODO: Создайте учетные данные для email.com
  // website: 'email.com', username: 'john_doe', password: 'myP@ss'
  
  // TODO: Вызовите displayCredential() для вторых учетных данных
  
  // TODO: Выведите фактическую длину пароля, используя публичный геттер
}
quiz iconПроверьте себя

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

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