CodeGym /Cursos /JAVA 25 SELF /Uso do polimorfismo na prática

Uso do polimorfismo na prática

JAVA 25 SELF
Nível 18, Lição 3
Disponível

1. Polimorfismo em coleções: para que serve?

Vamos começar com uma pergunta: “Afinal, para que serve o polimorfismo em programas reais?”

Imagine um zoológico. Você tem uma classe base Animal e um monte de subclasses: Dog, Cat, Cow, Parrot e até Platypus (ornitorrinco, para os amantes de exotismo). Cada um deles sabe emitir um som (makeSound()), mas faz isso à sua maneira.

Em vez de criar arrays separados para cada animal, você declara um array ou lista do tipo Animal e coloca ali quem quiser:

Animal[] animals = {
    new Dog(),
    new Cat(),
    new Cow(),
    new Parrot()
};

Agora você pode percorrer esse array e chamar makeSound() para cada um:

for (Animal animal : animals) {
    animal.makeSound();
}

Magia! Cada objeto sabe qual som emitir, e você não precisa escrever um monte de if ou switch.

Exemplo com analogia

É como se você desse o comando “Voz!” a um grupo de animais, e cada um decidisse sozinho o que fazer: o cachorro late, o gato mia e a vaca — muge. Você não especifica quem é quem — apenas chama o mesmo método.

2. Exemplo prático: hierarquia de funcionários

Vamos fazer um exemplo mais próximo da vida real (e do futuro trabalho em TI). Imagine que temos uma empresa com diferentes funcionários: gerentes, desenvolvedores, testadores. Cada um tem o método work(), mas ele é executado de forma diferente.

Declaração da classe base

public class Employee {
    public void work() {
        System.out.println("O funcionário está trabalhando...");
    }
}

Subclasses

public class Manager extends Employee {
    @Override
    public void work() {
        System.out.println("O gerente está conduzindo uma reunião.");
    }
}

public class Developer extends Employee {
    @Override
    public void work() {
        System.out.println("O desenvolvedor está escrevendo código.");
    }
}

public class Tester extends Employee {
    @Override
    public void work() {
        System.out.println("O testador está procurando bugs.");
    }
}

Usando um array/lista do tipo base

public class CompanyDemo {
    public static void main(String[] args) {
        Employee[] team = {
            new Manager(),
            new Developer(),
            new Tester(),
            new Developer()
        };

        for (Employee e : team) {
            e.work(); // Será chamada a versão "correta" do método para cada objeto
        }
    }
}

Resultado da execução:

O gerente está conduzindo uma reunião.
O desenvolvedor está escrevendo código.
O testador está procurando bugs.
O desenvolvedor está escrevendo código.

Quais são as vantagens?

  • Você não escreve um monte de verificações do tipo “Se for Developer — faça isso”.
  • Adicionar um novo funcionário (por exemplo, Designer) — basta criar uma classe nova e adicioná-lo ao array.
  • O código que usa o array de funcionários não muda em nada!

3. Vantagens do polimorfismo: flexibilidade e extensibilidade

Vamos imaginar que surgiu um novo tipo de funcionário na sua empresa — Designer. Tudo o que você precisa fazer é criar uma nova classe:

public class Designer extends Employee {
    @Override
    public void work() {
        System.out.println("O designer está criando layouts.");
    }
}

Agora você pode adicionar o designer à equipe:

Employee[] team = {
    new Manager(),
    new Developer(),
    new Tester(),
    new Designer()
};

Voilà! O programa passa a funcionar corretamente com o novo tipo de funcionário, sem mudar uma única linha no código que itera o array e chama work().

Isso é a extensibilidade: seu código se adapta facilmente a novos tipos de objetos.

4. Limitações do polimorfismo: o outro lado da moeda

Infelizmente, toda “magia” tem suas limitações (e um custo, como em qualquer RPG).

Apenas os métodos da classe base ficam disponíveis

Quando você trabalha com uma variável do tipo Employee, pode chamar apenas os métodos declarados na classe Employee. Se a classe Developer tiver um método específico writeCode(), você não conseguirá chamá-lo diretamente:

Employee e = new Developer();
// e.writeCode(); // Erro de compilação: esse método não existe em Employee!

Se você realmente quiser chamar um método específico, terá que fazer casting. Mas isso é um último recurso. Se você faz casts com frequência, talvez deva repensar o design das classes — a classe base ou a interface deveria conter o método necessário.

if (e instanceof Developer) {
    Developer dev = (Developer) e;
    dev.writeCode();
}

Mas aí você perde a universalidade e a elegância pela qual tudo isso foi pensado. Portanto, procure projetar a classe base de forma que ela tenha apenas os métodos que realmente são necessários a todos os herdeiros.

5. Prática: implementando a hierarquia de funcionários

Vamos unir o útil ao agradável: vamos escrever um aplicativo simples, com alguns tipos de funcionários, e usar polimorfismo para tratá-los.

Passo 1: classe base e subclasses

// Employee.java
public class Employee {
    public void work() {
        System.out.println("O funcionário está trabalhando...");
    }
}

// Manager.java
public class Manager extends Employee {
    @Override
    public void work() {
        System.out.println("O gerente está conduzindo uma reunião.");
    }
}

// Developer.java
public class Developer extends Employee {
    @Override
    public void work() {
        System.out.println("O desenvolvedor está escrevendo código.");
    }
}

// Tester.java
public class Tester extends Employee {
    @Override
    public void work() {
        System.out.println("O testador está procurando bugs.");
    }
}

Passo 2: classe principal

// CompanyDemo.java
public class CompanyDemo {
    public static void main(String[] args) {
        Employee[] team = {
            new Manager(),
            new Developer(),
            new Tester(),
            new Developer()
        };

        for (Employee e : team) {
            e.work();
        }
    }
}

Passo 3: adicionando extensibilidade

Suponha que, em um mês, apareça um novo funcionário — um designer. Tudo o que é preciso:

public class Designer extends Employee {
    @Override
    public void work() {
        System.out.println("O designer está criando layouts.");
    }
}

Pronto, agora você pode adicionar o designer à equipe:

Employee[] team = {
    new Manager(),
    new Developer(),
    new Tester(),
    new Designer()
};

Conclusão

Todo o código principal (CompanyDemo) permaneceu inalterado! Essa é a força do polimorfismo.

6. Erros comuns ao usar polimorfismo

Erro nº 1: Esperar acesso a métodos específicos por meio de uma referência do tipo base.
Muito frequentemente, iniciantes tentam chamar métodos específicos da subclasse por meio de uma variável do tipo da superclasse. Por exemplo:

Employee e = new Developer();
// e.writeCode(); // Erro! Esse método não está definido em Employee.

Para chamar um método específico, é preciso fazer casting, mas aí perde-se a universalidade.

Erro nº 2: Não usar a anotação @Override.
Se você esquecer a anotação, pode acidentalmente escrever um método novo em vez de sobrescrever (por exemplo, errar no nome). Nesse caso, o polimorfismo simplesmente não funcionará, e será chamada a versão da superclasse.

Erro nº 3: Ausência de uma interface comum.
Se a classe base não contiver o método necessário, o polimorfismo é impossível. Por exemplo, se em Employee não houver o método work(), o laço sobre o array de funcionários não conseguirá chamar esse método para todos.

Erro nº 4: Violação do princípio aberto/fechado.
Se, para adicionar um novo tipo de funcionário, for preciso mudar o código que percorre o array/lista, então você não está usando o polimorfismo corretamente.

1
Tarefa
JAVA 25 SELF, nível 18, lição 3
Bloqueado
Vozes da enciclopédia digital de animais
Vozes da enciclopédia digital de animais
1
Tarefa
JAVA 25 SELF, nível 18, lição 3
Bloqueado
Sinfonia Corporativa: Polimorfismo no trabalho dos funcionários
Sinfonia Corporativa: Polimorfismo no trabalho dos funcionários
1
Tarefa
JAVA 25 SELF, nível 18, lição 3
Bloqueado
Expansão da equipe: Adicionando um novo tipo de funcionário
Expansão da equipe: Adicionando um novo tipo de funcionário
1
Tarefa
JAVA 25 SELF, nível 18, lição 3
Bloqueado
Escritório Dinâmico: Extensibilidade e universalidade do polimorfismo
Escritório Dinâmico: Extensibilidade e universalidade do polimorfismo
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION