Mobile App Development · Dart/Flutter

21 · Mixins e Extensions — Desafios

Dois desafios que juntam múltiplos mixins em um componente interativo e extensions de e-commerce que encapsulam regras de negócio diretamente nos tipos nativos.

Desafio 1

desafio_01_componentes_interativos.dart

Modela componentes que podem registrar cliques e eventos usando mixins: Clicavel adiciona um contador de cliques e Rastreavel adiciona rastreamento de eventos de analytics. A classe BotaoCompra usa with para combinar os dois mixins e exibe um relatório no console.

// Desafio: criar componentes interativos com múltiplos mixins.
// Combina 'Clicavel' (contador de cliques) e 'Rastreavel' (rastreamento de eventos).

// Mixin que adiciona contagem de cliques ao componente.
mixin Clicavel {
  // Contador de quantas vezes o componente foi clicado.
  int cliques = 0;

  // Incrementa o contador a cada clique registrado.
  void clicar() {
    cliques++;
  }
}

// Mixin que adiciona rastreamento de eventos de analytics.
mixin Rastreavel {
  // Registra um evento com um nome descritivo.
  void rastrear(String evento) {
    print('Evento rastreado: $evento');
  }
}

// BotaoCompra usa ambos os mixins e adiciona lógica própria de negócio.
class BotaoCompra with Clicavel, Rastreavel {
  // Rótulo visível no botão (ex.: 'Comprar', 'Adicionar ao Carrinho').
  final String rotulo;

  BotaoCompra(this.rotulo);

  // Método que coordena o clique: incrementa contador e rastreia o evento.
  void pressionar() {
    clicar(); // Mixin Clicavel: incrementa cliques.
    rastrear('Botao $rotulo pressionado'); // Mixin Rastreavel: registra evento.
  }
}

void main() {
  BotaoCompra botao = BotaoCompra('Comprar');
  // Pressiona o botão duas vezes — cada chamada incrementa o contador.
  botao.pressionar();
  botao.pressionar();
  // Exibe o total de cliques acumulados pelo mixin Clicavel.
  print('Total de cliques: ${botao.cliques}');
}

Saída esperada

Evento rastreado: Botao Comprar pressionado
Evento rastreado: Botao Comprar pressionado
Total de cliques: 2

Como executar

dart run 21-Mixins_Extensions/03_Desafios/codigo_fonte/desafio_01_componentes_interativos.dart

Desafio 2

desafio_02_extensions_ecommerce.dart

Cria extensions para um cenário de e-commerce: Moeda sobre double formata preço e aplica desconto percentual, e ProdutoTexto sobre String normaliza o nome de um produto (remove espaços extras e ajusta capitalização). Os métodos são usados juntos em um resumo de produto.

// Desafio: criar extensions de e-commerce para double e String.
// Demonstra como encapsular lógica de negócio diretamente nos tipos nativos.

// Extension sobre double: métodos úteis para preços em e-commerce.
extension Moeda on double {
  // Formata o double como moeda brasileira com símbolo R$.
  String paraReal() => 'R\$ ${toStringAsFixed(2)}';

  // Aplica um desconto percentual ao preço e retorna o valor com desconto.
  // 'percentual' deve ser uma proporção: 0.10 = 10%, 0.15 = 15% etc.
  // 'this' refere-se ao double sobre o qual o método é chamado.
  double aplicarDesconto(double percentual) => this - (this * percentual);
}

// Extension sobre String: métodos úteis para formatação de nomes de produtos.
extension ProdutoTexto on String {
  // Formata a String como nome de produto: remove espaços extras e capitaliza a primeira letra.
  String nomeFormatado() {
    // trim() remove espaços em branco do início e fim da String.
    String texto = trim();

    // Se a String estiver vazia após o trim, retorna sem modificar.
    if (texto.isEmpty) {
      return texto;
    }

    // Primeira letra em maiúscula, restante em minúscula.
    return '${texto[0].toUpperCase()}${texto.substring(1).toLowerCase()}';
  }
}

void main() {
  // Exemplo: produto com espaços e caixa alta no início.
  String produto = '  TECLADO MECANICO';
  double preco = 250;
  // Aplica 10% de desconto: 250 - (250 * 0.10) = 225.0.
  double precoComDesconto = preco.aplicarDesconto(0.10);

  // nomeFormatado() trata espaços e converte para formato adequado.
  print('Produto: ${produto.nomeFormatado()}');
  // paraReal() formata o preço original com símbolo de reais.
  print('Preco original: ${preco.paraReal()}');
  // paraReal() formata o preço com desconto já aplicado.
  print('Preco com desconto: ${precoComDesconto.paraReal()}');
}

Saída esperada

Produto: Teclado mecanico
Preco original: R$ 250.00
Preco com desconto: R$ 225.00

Como executar

dart run 21-Mixins_Extensions/03_Desafios/codigo_fonte/desafio_02_extensions_ecommerce.dart