Запечатанные классы (Dart 3)
Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy — урок 85 из 110.
В Dart 3 появились запечатанные классы (sealed classes), которые ограничивают список классов, способных расширять или реализовывать их. Когда вы помечаете класс как sealed, только классы в том же файле могут быть его прямыми подтипами. Это создает закрытый набор известных подтипов.
sealed class Result {}
class Success extends Result {
final String data;
Success(this.data);
}
class Failure extends Result {
final String error;
Failure(this.error);
}Сила изолированных классов (sealed classes) заключается в проверке на полноту (exhaustiveness checking). Когда вы используете оператор switch для изолированного типа, компилятор знает все возможные подтипы и гарантирует, что вы обработаете каждый из них:
String handleResult(Result result) {
return switch (result) {
Success(data: var d) => 'Got: $d',
Failure(error: var e) => 'Error: $e',
};
// Дефолтный случай не нужен — компилятор знает, что все варианты обработаны!
}
void main() {
var success = Success('Hello');
var failure = Failure('Not found');
print(handleResult(success)); // Got: Hello
print(handleResult(failure)); // Error: Not found
}Если вы добавите новый подтип в sealed-класс, компилятор пометит каждый оператор switch, который его не обрабатывает. Это делает sealed-классы идеальными для моделирования состояний, результатов или любых сценариев с фиксированным набором вариантов. В отличие от абстрактных классов, sealed-классы гарантируют, что никакой внешний код не сможет добавить непредусмотренные подтипы.
Задание
ЛегкоДавайте создадим обработчик сетевых запросов, используя запечатанные (sealed) классы! Вы создадите типобезопасную систему, которая моделирует различные состояния сетевого ответа, гарантируя правильную обработку каждого возможного результата.
Вы организуете свой код в двух файлах:
response.dart: Создайте иерархию запечатанных классов, которая представляет все возможные состояния сетевого ответа:- Запечатанный класс с именем
NetworkResponse, который служит базой для всех типов ответов - Класс
Loading, который расширяетNetworkResponseи содержит полеString message(например, "Fetching data...") - Класс
Success, который расширяетNetworkResponseи содержит полеString dataи полеint statusCode - Класс
Error, который расширяетNetworkResponseи содержит полеString errorMessageи полеint errorCode
- Запечатанный класс с именем
main.dart: Импортируйте файл с ответами и создайте функцию, которая обрабатывает все типы ответов с помощью выражения switch:- Создайте функцию
handleResponse(NetworkResponse response), которая возвращаетString - Используйте выражение switch с сопоставлением с образцом (pattern matching) для обработки каждого случая:
- Для
Loading: вернитеStatus: [message] - Для
Success: вернитеSuccess ([statusCode]): [data] - Для
Error: вернитеError ([errorCode]): [errorMessage]
- Для
- Создайте три экземпляра ответов и выведите результат обработки каждого:
- Экземпляр
Loadingс сообщениемPlease wait... - Экземпляр
Successс даннымиUser profile loadedи кодом состояния200 - Экземпляр
Errorс сообщением об ошибкеNot foundи кодом ошибки404
- Экземпляр
- Создайте функцию
Прелесть запечатанных классов заключается в том, что компилятор гарантирует обработку каждого возможного типа ответа — ветка по умолчанию (default) не требуется!
Ожидаемый вывод:
Status: Please wait...
Success (200): User profile loaded
Error (404): Not foundПопробуйте сами
import 'response.dart';
// TODO: Создайте функцию handleResponse(NetworkResponse response)
// которая возвращает String
// Используйте выражение switch с сопоставлением с образцом для обработки каждого случая:
// - Для Loading: верните "Status: [message]"
// - Для Success: верните "Success ([statusCode]): [data]"
// - Для Error: верните "Error ([errorCode]): [errorMessage]"
void main() {
// TODO: Создайте экземпляр Loading с сообщением "Please wait..."
// TODO: Создайте экземпляр Success с данными "User profile loaded" и кодом состояния 200
// TODO: Создайте экземпляр Error с сообщением об ошибке "Not found" и кодом ошибки 404
// 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
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн Репозиторий