A Palavra-chave final para Classes
Parte da seção Programação Orientada a Objetos do Journey de Dart da Coddy. Lição 40 de 110.
Às vezes, você deseja impedir que uma classe seja estendida. A palavra-chave final, quando aplicada a uma classe, impede que qualquer outra classe herde dela.
final class DatabaseConnection {
String connectionString;
DatabaseConnection(this.connectionString);
void connect() {
print('Connected to $connectionString');
}
}
// Isso causaria um erro em tempo de compilação:
// class CustomConnection extends DatabaseConnection { }Marcar uma classe como final é útil quando estendê-la pode quebrar seu comportamento pretendido ou garantias de segurança. Por exemplo, uma classe que gerencia recursos sensíveis pode precisar garantir que seus métodos não sejam sobrescritos de maneiras inesperadas.
O Dart 3 também introduziu modificadores relacionados: base força as subclasses a usarem extends (não implements), e sealed restringe a herança à mesma biblioteca. Por enquanto, foque em final como a maneira mais simples de bloquear uma classe completamente.
Use classes final quando você tiver certeza de que o design da classe está completo e a herança causaria apenas problemas. No entanto, não exagere no seu uso - a maioria das classes se beneficia ao permanecer aberta para extensão.
Desafio
FácilVamos criar um sistema de configuração seguro que demonstra quando e por que você gostaria de impedir que uma classe seja estendida. Você criará uma classe final que gerencia as configurações da aplicação, garantindo que seu comportamento não possa ser alterado por meio de herança.
Você organizará seu código em dois arquivos:
config.dart: defina suas classes de configuração aqui:- Uma
final class AppConfigque não pode ser estendida. Ela deve ter uma propriedadeString appNamee uma propriedadeString version, um construtor que receba ambos os valores e um métododisplay()que imprima[appName] v[version] - Uma classe
Featureregular (não final) com uma propriedadeString namee uma propriedadebool enabled, um construtor para ambas e um métodostatus()que imprima[name]: [enabled ? 'ON' : 'OFF'] - Uma classe
ExperimentalFeatureque estendeFeaturee adiciona uma propriedadeString warning. Substituastatus()usando@overridepara primeiro chamar a versão da classe pai comsuper.status()e depois imprimirWarning: [warning]
- Uma
main.dart: importe seu arquivo de configuração e demonstre a diferença entre classes finais e regulares:- Crie uma
AppConfigcom appName'MyApp'e versão'2.0.1', depois chamedisplay() - Imprima uma linha vazia
- Crie uma
Featurecom nome'Dark Mode'e enabledtrue, depois chamestatus() - Imprima uma linha vazia
- Crie uma
ExperimentalFeaturecom nome'AI Assistant', enabledfalsee warning'May be unstable', depois chamestatus()
- Crie uma
Observe como AppConfig é marcada como final porque seu comportamento de configuração deve permanecer consistente e seguro — nenhuma subclasse deve ser capaz de alterar a forma como as configurações são gerenciadas. Enquanto isso, Feature permanece aberta para extensão, permitindo que ExperimentalFeature adicione um comportamento especializado.
Saída esperada:
MyApp v2.0.1
Dark Mode: ON
AI Assistant: OFF
Warning: May be unstableExperimente você mesmo
import 'config.dart';
void main() {
// TODO: Criar um AppConfig com appName 'MyApp' e version '2.0.1'
// Depois chamar display()
// TODO: Imprimir uma linha vazia
// TODO: Criar um Feature com name 'Dark Mode' e enabled true
// Depois chamar status()
// TODO: Imprimir uma linha vazia
// TODO: Criar um ExperimentalFeature com name 'AI Assistant',
// enabled false, e warning 'May be unstable'
// Depois chamar status()
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de OOP
Arquivos externosBibliotecas e importsIntrodução à OOPClasses vs. objetosA palavra-chave thisMétodosVariáveis de instânciaNoções básicas de construtoresRevisão - Calculadora simples4Segurança contra nulos
Introdução à segurança contra nulosAnulável vs. não anulávelOs operadores ? e !Palavra-chave Late e segurança contra nulosOperadores conscientes de nulosSegurança contra nulos em classesRecapitulação — Sistema de perfil de usuário7Classes Abstratas e Interfaces
Classes AbstratasMétodos AbstratosInterfaces em DartInterfaces ImplícitasImplementação vs. ExtensãoMúltiplas InterfacesRecapitulação - Calculadora de Formas10Coleções e Genéricos
Visão geral de List, Set e MapColeções com segurança de tiposClasses genéricasMétodos genéricosRestrições genéricasIterable e IteratorRecapitulação - Armazenamento genérico13Conceitos Avançados de OOP
Composição vs. HerançaMétodos de ExtensãoClasses ChamáveisClasses Seladas (Dart 3)Registros (Dart 3)Padrões e Correspondência (3.0)Enums com Métodos16Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses de Livros e Usuários2Construtores em Dart
Construtor padrãoConstrutores nomeadosListas de inicializaçãoConstrutores constantesConstrutores factoryConstrutores de redirecionamentoRevisão - Construtor de formas5Encapsulamento
Membros Públicos vs. PrivadosConvenção do Prefixo _Privacidade no Nível da BibliotecaAprofundamento em Getters e SettersOcultação de InformaçõesRecapitulação - Registros de Alunos8Mixins
Introdução a MixinsCriando MixinsUsando vários MixinsPalavra-chave on em MixinsMixin vs HerançaMixin vs InterfaceRecapitulação - Sistema de Animais11Métodos Especiais
Sobrescrita de toString()Sobrescrita de hashCode e ==Interface ComparableMétodo call()Sobrescrita de noSuchMethodRecapitulação - Coleção Personalizada14Padrões de Projeto – Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão Strategy3Propriedades de Classe
Membros de Instância vs. EstáticosCampos Final e ConstVariáveis LateMétodos e Campos EstáticosGetters e SettersRecapitulação - Gerenciador de Contas Bancárias6Herança
Herança BásicaA Palavra-chave superSobrescrita de MétodosA Anotação @overrideA Palavra-chave final para ClassesConstrutores e HerançaRecapitulação - Hierarquia de Funcionários9Polimorfismo
Fundamentos do polimorfismoPolimorfismo por meio de interfacesVerificação de tipos em tempo de execuçãoOs operadores is e asPalavra-chave covarianteRecapitulação — Processador de pagamentos12OOP Assíncrona
Futures e async/awaitNoções básicas de StreamsControladores de StreamConstrutores assíncronosAsync em métodos de classeRecapitulação — Buscador de dados15Padrões de Projeto — Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão RepositoryPratique por conta própria: Compilador de Dart online