Classes Seladas (Dart 3)
Parte da seção Programação Orientada a Objetos do Journey de Dart da Coddy. Lição 85 de 110.
O Dart 3 introduziu classes seladas, que restringem quais classes podem estendê-las ou implementá-las. Quando você marca uma classe como sealed, somente classes no mesmo arquivo podem ser seus subtipos diretos. Isso cria um conjunto fechado de subtipos conhecidos.
sealed class Result {}
class Success extends Result {
final String data;
Success(this.data);
}
class Failure extends Result {
final String error;
Failure(this.error);
}O poder das classes seladas vem da verificação de exaustividade. Quando você utiliza um switch em um tipo selado, o compilador conhece todos os subtipos possíveis e garante que você trate cada um deles:
String handleResult(Result result) {
return switch (result) {
Success(data: var d) => 'Got: $d',
Failure(error: var e) => 'Error: $e',
};
// Nenhum padrão é necessário - o compilador sabe que todos os casos estão cobertos!
}
void main() {
var success = Success('Hello');
var failure = Failure('Not found');
print(handleResult(success)); // Got: Hello
print(handleResult(failure)); // Error: Not found
}Se você adicionar um novo subtipo a uma classe selada, o compilador sinalizará toda instrução switch que não o tratar. Isso torna as classes seladas ideais para modelar estados, resultados ou qualquer cenário em que você tenha um conjunto fixo de variantes. Diferentemente das classes abstratas, as classes seladas garantem que nenhum código externo possa adicionar subtipos inesperados.
Desafio
FácilVamos criar um manipulador de requisições de rede usando classes seladas! Você criará um sistema seguro em relação aos tipos que modela diferentes estados de uma resposta de rede, garantindo que todo resultado possível seja tratado corretamente.
Você organizará seu código em dois arquivos:
response.dart: Crie uma hierarquia de classes seladas que represente todos os estados possíveis de uma resposta de rede:- Uma classe selada chamada
NetworkResponseque serve como base para todos os tipos de resposta - Uma classe
Loadingque estendeNetworkResponsecom um campoString message(por exemplo, "Fetching data...") - Uma classe
Successque estendeNetworkResponsecom um campoString datae um campoint statusCode - Uma classe
Errorque estendeNetworkResponsecom um campoString errorMessagee um campoint errorCode
- Uma classe selada chamada
main.dart: Importe seu arquivo de resposta e crie uma função que trate todos os tipos de resposta usando uma expressão switch:- Crie uma função
handleResponse(NetworkResponse response)que retorne umaString - Use uma expressão switch com correspondência de padrões para tratar cada caso:
- Para
Loading: retorneStatus: [message] - Para
Success: retorneSuccess ([statusCode]): [data] - Para
Error: retorneError ([errorCode]): [errorMessage]
- Para
- Crie três instâncias de resposta e imprima o resultado do tratamento de cada uma:
- Um
Loadingcom a mensagemPlease wait... - Um
Successcom os dadosUser profile loadede o código de status200 - Um
Errorcom a mensagem de erroNot founde o código de erro404
- Um
- Crie uma função
A vantagem das classes seladas é que o compilador garante que você trate todos os tipos de resposta possíveis — nenhum caso padrão é necessário!
Saída esperada:
Status: Please wait...
Success (200): User profile loaded
Error (404): Not foundExperimente você mesmo
import 'response.dart';
// TODO: Crie uma função handleResponse(NetworkResponse response)
// que retorna uma String
// Use uma switch expression com pattern matching para lidar com cada caso:
// - Para Loading: retorne "Status: [message]"
// - Para Success: retorne "Success ([statusCode]): [data]"
// - Para Error: retorne "Error ([errorCode]): [errorMessage]"
void main() {
// TODO: Crie uma instância de Loading com a mensagem "Please wait..."
// TODO: Crie uma instância de Success com os dados "User profile loaded" e o status code 200
// TODO: Crie uma instância de Error com a mensagem de erro "Not found" e o error code 404
// TODO: Imprima o resultado do tratamento de cada resposta
}
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