Menu
Coddy logo textTech

La parola chiave final per le classi

Fa parte della sezione Programmazione orientata agli oggetti del percorso Dart di Coddy. Lezione 40 di 110.

A volte vuoi impedire che una classe venga estesa. La parola chiave final, quando viene applicata a una classe, impedisce a qualsiasi altra classe di ereditarla.

final class DatabaseConnection {
  String connectionString;
  
  DatabaseConnection(this.connectionString);
  
  void connect() {
    print('Connected to $connectionString');
  }
}

// Questo causerebbe un errore in fase di compilazione:
// class CustomConnection extends DatabaseConnection { }

Contrassegnare una classe come final è utile quando estenderla potrebbe compromettere il comportamento previsto o le garanzie di sicurezza. Per esempio, una classe che gestisce risorse sensibili potrebbe dover garantire che i suoi metodi non vengano sovrascritti in modi imprevisti.

Dart 3 ha introdotto anche modificatori correlati: base obbliga le sottoclassi a usare extends (non implements) e sealed limita l'ereditarietà alla stessa libreria. Per ora, concentrati su final come modo più semplice per rendere una classe completamente immodificabile.

Usa le classi final quando sei certo che la progettazione della classe sia completa e che l'ereditarietà causerebbe solo problemi. Tuttavia, non abusarne: la maggior parte delle classi trae vantaggio dal rimanere aperta all'estensione.

challenge icon

Sfida

Facile

Costruiamo un sistema di configurazione sicuro che mostri quando e perché vorresti impedire che una classe venga estesa. Creerai una classe final che gestisce le impostazioni dell'applicazione, assicurandoti che il suo comportamento non possa essere modificato tramite ereditarietà.

Organizzerai il codice in due file:

  • config.dart: definisci qui le classi di configurazione:
    • Una final class AppConfig che non può essere estesa. Dovrebbe avere le proprietà String appName e String version, un costruttore che accetta entrambi i valori e un metodo display() che stampa [appName] v[version]
    • Una classe Feature normale (non final) con le proprietà String name e bool enabled, un costruttore che accetta entrambe e un metodo status() che stampa [name]: [enabled ? 'ON' : 'OFF']
    • Una classe ExperimentalFeature che estende Feature e aggiunge la proprietà String warning. Sovrascrivi status() usando @override per chiamare prima la versione della classe genitore con super.status(), quindi stampare Warning: [warning]
  • main.dart: importa il file di configurazione e mostra la differenza tra le classi final e quelle normali:
    • Crea un AppConfig con appName 'MyApp' e version '2.0.1', quindi chiama display()
    • Stampa una riga vuota
    • Crea un Feature con name 'Dark Mode' ed enabled true, quindi chiama status()
    • Stampa una riga vuota
    • Crea un ExperimentalFeature con name 'AI Assistant', enabled false e warning 'May be unstable', quindi chiama status()

Nota come AppConfig sia contrassegnata come final perché il suo comportamento di configurazione dovrebbe rimanere coerente e sicuro: nessuna sottoclasse dovrebbe poter modificare il modo in cui vengono gestite le impostazioni. Nel frattempo, Feature rimane aperta all'estensione, consentendo a ExperimentalFeature di aggiungere un comportamento specializzato.

Output previsto:

MyApp v2.0.1

Dark Mode: ON

AI Assistant: OFF
Warning: May be unstable

Provalo tu

import 'config.dart';

void main() {
  // TODO: Crea un AppConfig con appName 'MyApp' e versione '2.0.1'
  // Poi chiama display()
  
  // TODO: Stampa una riga vuota
  
  // TODO: Crea una Feature con nome 'Dark Mode' e enabled true
  // Poi chiama status()
  
  // TODO: Stampa una riga vuota
  
  // TODO: Crea una ExperimentalFeature con nome 'AI Assistant',
  // enabled false e warning 'May be unstable'
  // Poi chiama status()
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Dart online