Публичные и приватные члены
Часть раздела Объектно-ориентированное программирование путешествия по 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 нельзя получить прямой доступ извне библиотеки, в которой определен класс. Внешний код должен вместо этого использовать публичный геттер. Это позволяет вам контролировать, как данные считываются и изменяются, гарантируя, что ваши объекты всегда остаются в корректном состоянии.
Задание
ЛегкоДавайте создадим простой менеджер паролей, который демонстрирует разницу между публичными и приватными членами класса. Вы увидите, как префикс в виде нижнего подчеркивания защищает конфиденциальные данные от прямого доступа извне библиотеки класса.
Вы создадите два файла для организации вашего кода:
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: Выведите фактическую длину пароля, используя публичный геттер
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыБиблиотеки и импортВведение в ООПКлассы и объектыКлючевое слово thisМетодыПеременные экземпляраОсновы конструкторовИтоги — Простой калькулятор4Null-безопасность
Введение в Null-безопасностьNullable и Non-Nullable типыОператоры ? и !Ключевое слово Late и Null-безопасностьNull-aware операторыNull-безопасность в классахИтоги — Система профилей пользователей7Абстрактные классы и интерфейсы
Абстрактные классыАбстрактные методыИнтерфейсы в DartНеявные интерфейсыРеализация против наследованияМножественные интерфейсыИтоги — Калькулятор фигур10Коллекции и обобщения
Обзор List, Set, MapТипобезопасные коллекцииОбобщенные классыОбобщенные методыОграничения обобщенийIterable и IteratorИтоги: Обобщенное хранилище13Продвинутые концепции ООП
Композиция против наследованияМетоды расширенияВызываемые классыЗапечатанные классы (Dart 3)Записи (Dart 3)Паттерны и сопоставление (3.0)Перечисления с методами16Проект: Управление библиотекой
Обзор проектаКлассы Book и User2Конструкторы в Dart
Конструктор по умолчаниюИменованные конструкторыСписки инициализацииКонстантные конструкторыФабричные конструкторыПеренаправляющие конструкторыИтоги — Shape Builder5Инкапсуляция
Публичные и приватные членыСоглашение о префиксе _Приватность на уровне библиотекГеттеры и сеттеры: подробный разборСкрытие данныхИтоги — Записи о студентах8Mixins
Введение в MixinsСоздание MixinsИспользование нескольких MixinsКлючевое слово on в MixinsMixin и наследованиеMixin и интерфейсИтоги: Система животных11Специальные методы
Переопределение toString()Переопределение hashCode и ==Интерфейс ComparableМетод call()Переопределение noSuchMethodПовторение — Пользовательская коллекция14Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy3Свойства классов
Члены экземпляра и статические членыПоля Final и ConstПеременные LateСтатические методы и поляГеттеры и сеттерыИтоги — Менеджер банковского счета6Наследование
Основы наследованияКлючевое слово superПереопределение методовАннотация @overrideКлючевое слово final для классовКонструкторы и наследованиеИтоги: Иерархия сотрудников9Полиморфизм
Основы полиморфизмаПолиморфизм через интерфейсыПроверка типов во время выполненияОператоры is и asКлючевое слово covariantИтоги — Обработчик платежей12Асинхронное ООП
Futures и async/awaitОсновы StreamsКонтроллеры StreamАсинхронные конструкторыАсинхронность в методах классовИтоги — Data Fetcher15Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн Репозиторий