Defina classes e objetos
Aprenda sobre programação orientada a objetos em Dart, incluindo classes, construtores, getters e enums. Crie modelos de dados para argumentos de linha de comando.
Este capítulo aborda os fundamentos da programação orientada a objetos (POO) em Dart. Explore como criar classes, definir construtores e campos, calcular propriedades com gettersGetterUm método especial que oferece acesso de leitura às propriedades de um objeto. Saiba mais e usar enums para representar conjuntos fixos de valores.
O que você vai realizar
Pré-requisitos
#Antes de começar este capítulo:
-
Complete o Capítulo 4 e tenha um ambiente de desenvolvimento Dart
funcionando com o projeto
dartpedia. - Entenda conceitos básicos de programação, como variáveis, funções e controle de fluxo.
- Entenda pacotes e bibliotecas em Dart.
Classes e objetos em Dart
#Classes reúnem dois componentes principais:
-
Estado (campos):
Os dados que cada objeto guarda,
como o
nameou o texto dehelpde uma opção. -
Comportamento (métodos e getters):
As ações que um objeto pode executar ou as propriedades que ele calcula,
como formatar uma string de
usage.
Em vez de controlar strings ou mapas soltos ao longo de uma aplicação, modelar argumentos de linha de comando como classes garante segurança de tipos em tempo de compilação, autocompletar no editor e uma estrutura de dados consistente.
Tarefas
#Uma interface de linha de comando (CLI) é definida pelos comandos, opções e argumentos digitados em um terminal.
Esta lição e a próxima constroem um framework capaz de analisar um comando como:
$ dartpedia help --verbose --command=search
Cada parte tem uma função distinta:
-
dartpedia: O executável, ou o nome da aplicação. -
help: Um comando, representando uma ação a ser executada. -
--verbose: Uma flag (uma opção booleana sem valor), que modifica o comportamento do comando. -
--command=search: Uma opção que aceita um valor (search).
Este capítulo constrói os modelos de dados que representam as opções e os resultados analisados.
Tarefa 1: Defina o enum OptionType
#
Opções de linha de comando se dividem em duas categorias distintas:
flags (que valem true ou false) e
opções comuns (que aceitam um valor de texto).
Usar um enum garante que o código aceite apenas essas duas categorias válidas.
Crie
command_runner/lib/src/arguments.dart.-
Defina o enum
OptionType:command_runner/lib/src/arguments.dartdartenum OptionType { flag, option }Esta enumeração define dois membros:
flageoption. Enums oferecem segurança de tipos em tempo de compilação, garantindo que o código aceite apenas tipos de opção válidos.
Tarefa 2: Defina a classe Option
#
Classes em Dart definem blueprints para objetos,
combinando estado (campos) e comportamento (métodos e getters).
A classe Option modela opções de linha de comando como
--verbose ou --command=search.
-
Comece definindo uma classe
Optionmínima com os campos essenciais e um construtor. Adicione o código a seguir emcommand_runner/lib/src/arguments.dart, abaixo do enum:command_runner/lib/src/arguments.dartdartclass Option { Option(this.name, {required this.type}); final String name; final OptionType type; }- Campos (
final String name;,final OptionType type;): Variáveis que guardam os dados do objeto. Declará-los comofinalgarante que não mudem após a criação. - Construtor (
Option(...)): Instancia novos objetosOption. A sintaxethis.nameé um initializing formal, um atalho do Dart que atribui o argumento diretamente ao campo da instância antes de o corpo do construtor ser executado. - Parâmetros nomeados (
{required this.type}): Parâmetros entre chaves{}são passados pelo nome (por exemplo,Option('verbose', type: OptionType.flag)). A palavra-chaverequiredtorna o parâmetro obrigatório.
- Campos (
-
Agora, expanda a classe
Optioncom campos de metadados opcionais e um getterusage:command_runner/lib/src/arguments.dartdartclass Option { Option( this.name, { required this.type, this.help, this.abbr, this.defaultValue, this.valueHelp, }); final String name; final OptionType type; final String? help; final String? abbr; final Object? defaultValue; final String? valueHelp; String get usage { if (abbr != null) { return '-$abbr,--$name: $help'; } return '--$name: $help'; } }- Tipos anuláveis (
String?,Object?): O ponto de interrogação?indica que um campo é opcional e pode conternull. Quando quem chama omitehelpouabbr, eles assumemnull. - Getter (
get usage): Um getter calcula um valor sob demanda, quando é acessado, formatando a string de ajuda conforme exista ou não uma abreviação.
- Tipos anuláveis (
Tarefa 3: Defina a classe ArgResults
#
A classe ArgResults armazena o resultado da análise da entrada
de linha de comando.
Ela associa cada Option ao valor informado pelo usuário.
-
Adicione
ArgResultsao final decommand_runner/lib/src/arguments.dart:command_runner/lib/src/arguments.dartdartclass ArgResults { String? command; String? commandArg; Map<Option, Object?> options = {}; // Returns true if the flag exists and is true. bool flag(String name) { for (var option in options.keys.where( (option) => option.type == OptionType.flag, )) { if (option.name == name) { return options[option] as bool; } } return false; } bool hasOption(String name) { return options.keys.any((option) => option.name == name); } ({Option option, Object? input}) getOption(String name) { var mapEntry = options.entries.firstWhere( (entry) => entry.key.name == name || entry.key.abbr == name, ); return (option: mapEntry.key, input: mapEntry.value); } }Destaques do código anterior:
- Mapa
options(Map<Option, Object?>): Associa cada instância deOptionà sua entrada analisada. - Método
where()emflag(): Filtra as chaves do mapa para inspecionar apenas flags booleanas (option.type == OptionType.flag), ignorando opções que recebem argumentos de texto. - Cast de tipo (
as bool): Informa ao verificador de tipos que o valor deve ser tratado comobool, porque flags sempre armazenam valores booleanos. - Tipo de retorno de record (
({Option option, Object? input})): Retorna um record leve e nomeado, que agrupa aOptione o seu valor, sem precisar declarar uma classe separada.
A classe
ArgResultsserve como contrato de dados para a saída analisada. O Capítulo 6 conecta essa classe aoCommandRunnercompleto. - Mapa
Tarefa 4: Exporte os argumentos do pacote
#
Exporte arguments.dart a partir do ponto de entrada do pacote,
para que outros pacotes possam importar Option e ArgResults.
Abra
command_runner/lib/command_runner.dart.-
Exporte
arguments.dartjunto comcommand_runner_base.dart:command_runner/lib/command_runner.dartdart/// Support for command-line parsing and execution. library; export 'src/arguments.dart'; export 'src/command_runner_base.dart';Esta instrução
exporttorna as declarações dearguments.dartacessíveis a qualquer pacote que importepackage:command_runner/command_runner.dart.
Tarefa 5: Teste as classes em cli.dart
#Verifique se Option é instanciada e calcula corretamente a string usage.
Abra
cli/bin/cli.dart.-
Substitua o conteúdo do arquivo pelo código de teste a seguir:
cli/bin/cli.dartdartimport 'package:command_runner/command_runner.dart'; void main() { final verboseOption = Option( 'verbose', type: OptionType.flag, abbr: 'v', help: 'Display extra logging information.', ); print('Defined option: ${verboseOption.name}'); print('Usage: ${verboseOption.usage}'); }Este código chama o construtor de
Optionpara criar uma instância e depois imprime o camponamee o getterusagecalculado. -
Execute a aplicação a partir do diretório
cli:bashdart run bin/cli.dartO console mostra:
bashDefined option: verbose Usage: -v,--verbose: Display extra logging information.Isso confirma que a classe
Optione o getter funcionam como esperado.
Revisão
#O que você realizou
Um resumo dos conceitos e do código introduzidos nesta lição.Definiu classes para modelar dados e comportamento
Criou as classes Option e ArgResults para estruturar os argumentos de linha de comando e a saída analisada.
Criou construtores com initializing formals e parâmetros nomeados
Usou a sintaxe this.fieldName para inicialização automática de campos e definiu parâmetros nomeados opcionais e obrigatórios com
{} e required.
Usou getters para calcular propriedades dinamicamente
Implementou o getter usage para formatar o texto de ajuda da opção sob demanda, sem armazenar estado de string duplicado.
Usou enums para representar conjuntos fixos de valores
Definiu o enum OptionType para representar os tipos de opção válidos (flag e
option), garantindo segurança em tempo de compilação.
Quiz
#Check your understanding
1 / 3Option(this.name, {required this.type}), qual é a finalidade da sintaxe this.name?
-
Ela atribui automaticamente o argumento do construtor diretamente ao campo de instância
name.Isso mesmo!
No Dart,
this.nomeDoCampona lista de parâmetros de um construtor é um "parâmetro formal de inicialização" que atribui o valor do argumento diretamente ao campo antes de o corpo do construtor executar. -
Ela cria uma nova variável global chamada
name.Não exatamente.
this.namese refere especificamente ao campo de instância da classe, e não a uma variável global. -
Ela torna a propriedade
nameprivada para a biblioteca.Não exatamente.
A privacidade no Dart é indicada por um underscore no início (
_name), e não porthis. -
Ela marca o parâmetro como opcional.
Não exatamente.
Parâmetros opcionais são delimitados por colchetes
[]ou chaves{}. Othis.nameposicional é obrigatório.
String get usage em vez de guardar um campo String usage?
-
Ele calcula o valor dinamicamente sempre que é acessado, garantindo que reflita o estado atual sem armazenamento redundante.
Isso mesmo!
Getters se comportam como propriedades do ponto de vista de quem chama, mas executam código sob demanda para calcular o valor.
-
Getters só podem ser acessados de dentro do mesmo arquivo.
Não exatamente.
Getters seguem as mesmas regras de visibilidade que campos e métodos comuns.
-
Getters executam mais rápido do que a leitura de um campo armazenado.
Não exatamente.
Ler um campo armazenado costuma ser mais rápido do que executar lógica em um getter.
-
Getters permitem que a propriedade seja modificada de fora da classe.
Não exatamente.
Um getter oferece acesso somente leitura, a menos que um setter correspondente (
set usage(...)) também seja definido.
enum em vez de uma classe ou de um conjunto de constantes?
-
Quando você precisa de um tipo que pode ser apenas um de um conjunto fixo e conhecido de valores.
Isso mesmo!
Enums são ideais quando você tem um conjunto fechado de opções, como
flagouoption, dias da semana ou códigos de status. O compilador garante que você trate todos os casos. -
Quando você precisa guardar uma entrada do usuário que pode ser qualquer string.
Não exatamente.
A entrada do usuário é imprevisível e pode ser qualquer coisa. Enums funcionam melhor quando você consegue listar todos os valores possíveis com antecedência.
-
Quando você quer criar várias instâncias com propriedades diferentes.
Não exatamente.
Para isso servem as classes. Cada valor de enum é um singleton: existe apenas uma instância para cada valor.
-
Quando você precisa fazer operações aritméticas com os valores.
Não exatamente.
Use
intoudoublepara aritmética. Enums representam categorias distintas, e não valores numéricos (embora tenham um índice).
Próxima lição
#
O próximo capítulo aborda como compartilhar comportamento entre classes
usando herança e classes abstratas.
Defina uma classe base abstrata CliElement e
construa a arquitetura Command e CommandRunner.
Salvo indicação em contrário, a documentação neste site reflete Dart 3.13.7. Página atualizada pela última vez em 2026-11-12. Ver código-fonte ou relatar um problema.
Encontrou essa página sem tradução ou que precisa de correção? Abra uma issue e nos ajude a manter esse site em PT-BR para ajudar pessoas como você.