Mobile App Development · Dart/Flutter
Seis exercícios progressivos: de um mixin simples até múltiplos mixins, mixin com estado, on e extensions em String e double.
Exercício 1
Cria o mixin Logavel com um método log e aplica em ServicoUsuario usando with. Mostra a forma mais básica de compartilhar comportamento entre classes sem herança.
// Demonstração de Mixin básico em Dart.
// Mixin é um mecanismo de reutilização de código que permite adicionar
// comportamentos a uma classe sem usar herança direta.
// Declarado com 'mixin'; aplicado em uma classe com 'with'.
// Define o mixin 'Logavel' com o comportamento de registrar logs.
mixin Logavel {
// Método que pode ser usado por qualquer classe que aplique este mixin.
void log(String mensagem) {
print('[LOG] $mensagem');
}
}
// 'with Logavel' adiciona o comportamento de log à classe ServicoUsuario
// sem precisar criar uma classe base em comum.
class ServicoUsuario with Logavel {
void buscarUsuario() {
// Chama o método 'log' herdado do mixin Logavel.
log('Buscando usuario');
}
}
void main() {
ServicoUsuario servico = ServicoUsuario();
// Chama o método do serviço que internamente usa o mixin.
servico.buscarUsuario();
}
Saída esperada
[LOG] Buscando usuario
Como executar
dart run 21-Mixins_Extensions/02_Exercicios/codigo_fonte/exercicio_01_mixin_logavel.dart
Exercício 2
Cria dois mixins independentes, Logavel e Auditavel, e aplica ambos na mesma classe com with Logavel, Auditavel. Mostra que uma classe pode combinar vários comportamentos de mixins diferentes.
// Demonstração de múltiplos mixins em uma única classe.
// Uma classe pode aplicar vários mixins usando 'with Mixin1, Mixin2, ...'.
// Cada mixin adiciona seus comportamentos de forma independente.
// Mixin para registro de mensagens de log.
mixin Logavel {
// Arrow function: forma compacta de definir método com única expressão.
void log(String mensagem) => print('[LOG] $mensagem');
}
// Mixin para registro de ações de auditoria.
mixin Auditavel {
void auditar(String acao) => print('[AUDITORIA] $acao');
}
// A classe PedidoService herda comportamentos dos dois mixins simultaneamente.
// 'with Logavel, Auditavel' mescla ambos os comportamentos.
class PedidoService with Logavel, Auditavel {
void criarPedido() {
// Usa o método do mixin Logavel.
log('Criando pedido');
// Usa o método do mixin Auditavel.
auditar('Pedido criado');
}
}
void main() {
PedidoService service = PedidoService();
// Chama criarPedido que internamente aciona os dois mixins.
service.criarPedido();
}
Saída esperada
[LOG] Criando pedido [AUDITORIA] Pedido criado
Como executar
dart run 21-Mixins_Extensions/02_Exercicios/codigo_fonte/exercicio_02_multiplos_mixins.dart
Exercício 3
Cria o mixin ContadorCliques, que declara o atributo cliques além do método registrarClique. Mostra que mixins também podem carregar estado, não apenas comportamento — cada classe que os usa recebe sua própria cópia.
// Demonstração de mixin com estado (atributo) em Dart.
// Mixins não precisam ser apenas comportamentos sem estado —
// eles também podem declarar atributos que ficam disponíveis nas classes que os usam.
// Mixin que adiciona um contador de cliques às classes que o aplicam.
mixin ContadorCliques {
// Atributo de estado que pertence ao mixin — cada instância tem o seu.
int cliques = 0;
// Método que incrementa o contador a cada chamada.
void registrarClique() {
cliques++;
}
}
// A classe Botao ganha o atributo 'cliques' e o método 'registrarClique'
// diretamente do mixin, sem precisar declarar nada.
class Botao with ContadorCliques {}
void main() {
Botao botao = Botao();
// Chama registrarClique duas vezes — o contador interno aumenta.
botao.registrarClique();
botao.registrarClique();
// Acessa o atributo 'cliques' que veio do mixin — resultado: 2.
print('Cliques: ${botao.cliques}');
}
Saída esperada
Cliques: 2
Como executar
dart run 21-Mixins_Extensions/02_Exercicios/codigo_fonte/exercicio_03_mixin_com_estado.dart
Exercício 4
Cria a classe base Entidade e o mixin Identificavel, restrito com on Entidade. Isso garante que o mixin só possa ser usado por subclasses de Entidade, permitindo acessar com segurança o atributo id definido na base.
// Demonstração de 'mixin on' — restrição de uso de mixin.
// 'mixin X on Y' significa que X só pode ser aplicado a classes que estendem Y.
// Isso garante que o mixin acesse membros definidos na classe base.
// Classe base com o atributo 'id' que o mixin vai acessar.
class Entidade {
final String id;
Entidade(this.id);
}
// 'on Entidade' restringe: apenas classes que herdam de Entidade podem usar este mixin.
// Dentro do mixin, podemos acessar 'id' porque garantidamente a classe base o tem.
mixin Identificavel on Entidade {
void exibirId() {
// 'id' é acessível porque o mixin só pode ser usado por subclasses de Entidade.
print('ID: $id');
}
}
// Produto herda de Entidade (necessário para aplicar Identificavel) e usa o mixin.
class Produto extends Entidade with Identificavel {
// 'super.id' passa o valor do parâmetro para o construtor da classe pai (Entidade).
Produto(super.id);
}
void main() {
Produto produto = Produto('prod-001');
// Chama o método do mixin que acessa o atributo da classe base.
produto.exibirId();
}
Saída esperada
ID: prod-001
Como executar
dart run 21-Mixins_Extensions/02_Exercicios/codigo_fonte/exercicio_04_mixin_on.dart
Exercício 5
Cria a extension TextoFormatado sobre String, adicionando o método capitalizar, que transforma o primeiro caractere em maiúsculo. Mostra como estender um tipo nativo do Dart sem herança.
// Demonstração de Extension Method em Dart sobre o tipo String.
// Extensions permitem adicionar novos métodos a tipos existentes
// sem modificar o código original da classe e sem herança.
// 'extension NomeDaExtension on Tipo' adiciona métodos ao tipo especificado.
extension TextoFormatado on String {
// Novo método 'capitalizar' adicionado ao tipo String.
// Converte o primeiro caractere para maiúscula e mantém o resto intacto.
String capitalizar() {
// Verifica se a String está vazia — nesse caso, retorna ela mesma sem alteração.
if (isEmpty) {
return this;
}
// this[0] acessa o primeiro caractere.
// toUpperCase() converte para maiúscula.
// substring(1) retorna a String a partir do segundo caractere.
return '${this[0].toUpperCase()}${substring(1)}';
}
}
void main() {
String nome = 'dart';
// 'capitalizar()' agora está disponível em qualquer String!
// Resultado esperado: 'Dart'.
print(nome.capitalizar());
}
Saída esperada
Dart
Como executar
dart run 21-Mixins_Extensions/02_Exercicios/codigo_fonte/exercicio_05_extension_string.dart
Exercício 6
Cria a extension Moeda sobre double, adicionando o método paraReal, que formata o valor como moeda brasileira com duas casas decimais. Mostra extensions aplicadas a tipos numéricos.
// Demonstração de Extension Method em Dart sobre o tipo double.
// Adiciona funcionalidades de formatação monetária diretamente ao tipo double.
// Estende o tipo double com método de formatação em reais (R$).
extension Moeda on double {
// Converte o valor double para uma String formatada como moeda brasileira.
// Arrow function: implementação compacta com uma única expressão de retorno.
// toStringAsFixed(2) garante sempre 2 casas decimais (ex.: 49.90).
String paraReal() => 'R\$ ${toStringAsFixed(2)}';
}
void main() {
double preco = 49.9;
// 'paraReal()' agora está disponível em qualquer double!
// Resultado esperado: 'R$ 49.90'.
print(preco.paraReal());
}
Saída esperada
R$ 49.90
Como executar
dart run 21-Mixins_Extensions/02_Exercicios/codigo_fonte/exercicio_06_extension_double.dart