Menu
Coddy logo textTech

Classes Genéricas

Parte da seção Programação Orientada a Objetos do Journey de Dart da Coddy — lição 65 de 110.

Você viu como as coleções integradas do Dart, como List<String>, usam parâmetros de tipo. Agora é hora de criar suas próprias classes genéricas que funcionam com qualquer tipo que você especificar.

Uma classe genérica usa um parâmetro de tipo (tipicamente T) como um marcador de posição para o tipo real que será fornecido ao criar uma instância:

class Box<T> {
  T content;
  
  Box(this.content);
  
  T getContent() => content;
}

void main() {
  var stringBox = Box<String>('Hello');
  var intBox = Box<int>(42);
  
  print(stringBox.getContent());  // Hello
  print(intBox.getContent());     // 42
}

O T atua como uma variável de tipo - quando você cria Box<String>, cada T na classe torna-se String. Isso oferece segurança de tipos sem a necessidade de escrever classes separadas para cada tipo.

Você pode usar múltiplos parâmetros de tipo quando sua classe precisa trabalhar com mais de um tipo:

class Pair<K, V> {
  K first;
  V second;
  
  Pair(this.first, this.second);
}

void main() {
  var pair = Pair<String, int>('age', 25);
  print('${pair.first}: ${pair.second}');  // age: 25
}

Classes genéricas são a base de um código reutilizável e com segurança de tipos. Em vez de duplicar a lógica para tipos diferentes ou perder informações de tipo com dynamic, os genéricos permitem que você escreva um código flexível que o compilador ainda pode verificar.

challenge icon

Desafio

Fácil

Vamos construir um sistema de embrulho de presentes que utiliza classes genéricas para criar contêineres flexíveis para diferentes tipos de itens. Você criará uma classe genérica Wrapper que pode embrulhar qualquer tipo de conteúdo, e uma classe GiftBox com dois parâmetros de tipo para emparelhar um presente com uma mensagem de cartão.

Você organizará seu código em dois arquivos:

  • wrapper.dart: Defina suas classes genéricas aqui:
    • Uma classe genérica Wrapper<T> com uma propriedade T content e um construtor. Inclua um método unwrap() que retorna o conteúdo, e um método describe() que imprime Wrapped: [content]
    • Uma classe genérica GiftBox<G, C> com duas propriedades: G gift e C card. Inclua um construtor e um método open() que imprime Gift: [gift] em uma linha e Card: [card] na linha seguinte
  • main.dart: Importe seu arquivo wrapper e demonstre as classes genéricas com diferentes tipos:
    • Crie um Wrapper<String> contendo 'Chocolate' e chame describe()
    • Crie um Wrapper<int> contendo 42 e chame describe()
    • Crie um Wrapper<double> contendo 3.14 e chame describe()
    • Imprima uma linha vazia
    • Crie um GiftBox<String, String> com o presente 'Teddy Bear' e o cartão 'Happy Birthday!', então chame open()
    • Imprima uma linha vazia
    • Crie um GiftBox<int, String> com o presente 100 (representando o valor de um cartão-presente) e o cartão 'Congratulations!', então chame open()

Observe como a mesma classe Wrapper funciona perfeitamente com strings, inteiros e doubles. A classe GiftBox demonstra o uso de dois parâmetros de tipo para emparelhar tipos diferentes - o presente pode ser de qualquer tipo, enquanto a mensagem do cartão permanece uma string.

Saída esperada:

Wrapped: Chocolate
Wrapped: 42
Wrapped: 3.14

Gift: Teddy Bear
Card: Happy Birthday!

Gift: 100
Card: Congratulations!

Folha de consulta

Classes genéricas usam parâmetros de tipo (como T) como espaços reservados para tipos reais especificados ao criar instâncias:

class Box<T> {
  T content;
  
  Box(this.content);
  
  T getContent() => content;
}

void main() {
  var stringBox = Box<String>('Hello');
  var intBox = Box<int>(42);
  
  print(stringBox.getContent());  // Hello
  print(intBox.getContent());     // 42
}

Quando você cria Box<String>, cada T na classe se torna String, fornecendo segurança de tipo sem a necessidade de classes separadas para cada tipo.

Use múltiplos parâmetros de tipo ao trabalhar com mais de um tipo:

class Pair<K, V> {
  K first;
  V second;
  
  Pair(this.first, this.second);
}

void main() {
  var pair = Pair<String, int>('age', 25);
  print('${pair.first}: ${pair.second}');  // age: 25
}

Experimente você mesmo

import 'wrapper.dart';

void main() {
  // TODO: Crie um Wrapper<String> contendo 'Chocolate' e chame describe()
  
  // TODO: Crie um Wrapper<int> contendo 42 e chame describe()
  
  // TODO: Crie um Wrapper<double> contendo 3.14 e chame describe()
  
  // TODO: Imprima uma linha vazia
  
  // TODO: Crie um GiftBox<String, String> com o presente 'Teddy Bear' 
  // e o cartão 'Happy Birthday!', depois chame open()
  
  // TODO: Imprima uma linha vazia
  
  // TODO: Crie um GiftBox<int, String> com o presente 100 
  // e o cartão 'Congratulations!', depois chame open()
}
quiz iconTeste seus conhecimentos

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