Ключевое слово final для классов
Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy — урок 40 из 110.
Иногда вы хотите запретить расширение класса. Ключевое слово final, примененное к классу, не позволяет любому другому классу наследоваться от него.
final class DatabaseConnection {
String connectionString;
DatabaseConnection(this.connectionString);
void connect() {
print('Connected to $connectionString');
}
}
// Это приведет к ошибке компиляции:
// class CustomConnection extends DatabaseConnection { }Пометка класса как final полезна в тех случаях, когда его расширение может нарушить предполагаемое поведение или гарантии безопасности. Например, классу, управляющему конфиденциальными ресурсами, может потребоваться гарантия того, что его методы не будут переопределены непредвиденным образом.
Dart 3 также представил связанные модификаторы: base заставляет подклассы использовать extends (а не implements), а sealed ограничивает наследование той же библиотекой. На данный момент сосредоточьтесь на final как на самом простом способе полностью заблокировать класс.
Используйте final классы, когда вы уверены, что дизайн класса завершен и наследование принесет только проблемы. Однако не злоупотребляйте этим — большинству классов полезно оставаться открытыми для расширения.
Задание
ЛегкоДавайте создадим безопасную систему конфигурации, которая продемонстрирует, когда и почему стоит запрещать наследование классов. Вы создадите финальный класс (final class) для управления настройками приложения, гарантируя, что его поведение не может быть изменено через наследование.
Вы организуете свой код в двух файлах:
config.dart: Определите здесь ваши классы конфигурации:- Класс
final class AppConfig, который нельзя расширять. Он должен иметь свойстваString appNameиString version, конструктор, принимающий оба значения, и методdisplay(), который выводит[appName] v[version] - Обычный (не финальный) класс
Featureсо свойствамиString nameиbool enabled, конструктором для обоих свойств и методомstatus(), который выводит[name]: [enabled ? 'ON' : 'OFF'] - Класс
ExperimentalFeature, который расширяетFeatureи добавляет свойствоString warning. Переопределитеstatus(), используя@override, чтобы сначала вызвать родительскую версию черезsuper.status(), а затем вывестиWarning: [warning]
- Класс
main.dart: Импортируйте файл конфигурации и продемонстрируйте разницу между финальными и обычными классами:- Создайте
AppConfigс appName'MyApp'и version'2.0.1', затем вызовитеdisplay() - Выведите пустую строку
- Создайте
Featureс name'Dark Mode'и enabledtrue, затем вызовитеstatus() - Выведите пустую строку
- Создайте
ExperimentalFeatureс name'AI Assistant', enabledfalseи warning'May be unstable', затем вызовитеstatus()
- Создайте
Обратите внимание, что AppConfig помечен как final, потому что поведение его конфигурации должно оставаться неизменным и безопасным — ни один подкласс не должен иметь возможности изменить способ управления настройками. В то же время Feature остается открытым для расширения, позволяя ExperimentalFeature добавлять специализированное поведение.
Ожидаемый вывод:
MyApp v2.0.1
Dark Mode: ON
AI Assistant: OFF
Warning: May be unstableШпаргалка
Ключевое слово final предотвращает наследование класса:
final class DatabaseConnection {
String connectionString;
DatabaseConnection(this.connectionString);
void connect() {
print('Connected to $connectionString');
}
}
// Это вызовет ошибку компиляции:
// class CustomConnection extends DatabaseConnection { }Используйте final классы, когда их расширение может нарушить предполагаемое поведение или гарантии безопасности. Большинство классов должны оставаться открытыми для расширения, если нет конкретной причины их ограничивать.
Dart 3 также предоставляет модификаторы base (заставляет подклассы использовать extends) и sealed (ограничивает наследование той же библиотекой).
Попробуйте сами
import 'config.dart';
void main() {
// TODO: Создайте AppConfig с appName 'MyApp' и version '2.0.1'
// Затем вызовите display()
// TODO: Выведите пустую строку
// TODO: Создайте Feature с name 'Dark Mode' и enabled true
// Затем вызовите status()
// TODO: Выведите пустую строку
// TODO: Создайте ExperimentalFeature с name 'AI Assistant',
// enabled false и warning 'May be unstable'
// Затем вызовите status()
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
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
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн Репозиторий