Menu
Coddy logo textTech

Ключевое слово 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 классы, когда вы уверены, что дизайн класса завершен и наследование принесет только проблемы. Однако не злоупотребляйте этим — большинству классов полезно оставаться открытыми для расширения.

challenge icon

Задание

Легко

Давайте создадим безопасную систему конфигурации, которая продемонстрирует, когда и почему стоит запрещать наследование классов. Вы создадите финальный класс (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' и enabled true, затем вызовите status()
    • Выведите пустую строку
    • Создайте ExperimentalFeature с name 'AI Assistant', enabled false и 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()
}
quiz iconПроверьте себя

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

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