Atividade 04: Prototype
Exercício 1: Aplicações
Seção intitulada “Exercício 1: Aplicações”Para cada cenário abaixo, indique se o padrão Prototype é apropriado ou não e justifique em 2–3 frases.
- Um sistema de relatórios financeiros em que os relatórios mensais nascem de um template base com cabeçalho, rodapé e seções padrão, mudando apenas os valores de cada mês.
- Uma classe simples
Pontocom apenas dois campos obrigatórios (x,y), utilizada em um sistema de CAD e instanciada dezenas de vezes por segundo. - Um sistema de jogos em que os inimigos possuem muita configuração (estatísticas, equipamentos, habilidades) e várias fases criam variações de um mesmo guerreiro repetindo o mesmo código de construção.
- Um módulo em que o cliente não deve conhecer as classes concretas dos objetos que precisa, podendo apenas pedir uma cópia pelo nome do modelo (por exemplo,
"guerreiro","mago") através de um registro. - Uma classe
Produtocom três campos obrigatórios (nome,preco,quantidadeEstoque), criada em um único ponto do sistema através do construtor tradicional e sem variações.
Para cada item, responda:
- “Faz sentido usar Prototype” ou “Não faz sentido usar Prototype”.
- Explique rapidamente o porquê (custo de criação, repetição de configuração, variações sobre uma base, acoplamento, overengineering, etc.).
Exercício 2: Analogia
Seção intitulada “Exercício 2: Analogia”Crie uma analogia própria para explicar o padrão Prototype para alguém que não é da área de TI.
Na aula, usamos a mitose (uma célula origina outra semelhante, o modelo participa da criação da cópia e a nova versão nasce pronta para uso). Agora crie uma outra analogia.
Descreva uma situação do mundo real em que:
- um objeto já pronto sirva de modelo para gerar cópias,
- as cópias nasçam completas e prontas para uso (sem reconstruir do zero),
- e a partir da mesma base seja possível gerar variações mudando apenas alguns detalhes.
Exercício 3: Anti-pattern
Seção intitulada “Exercício 3: Anti-pattern”Considere o código Java abaixo, usado em um jogo para criar os inimigos de cada fase:
public class Fase { private Inimigo criarCopia(Inimigo antigo) { Inimigo copia = new Inimigo(); copia.setTipo(antigo.getTipo()); copia.setVida(antigo.getVida()); copia.setDano(antigo.getDano()); copia.setArma(antigo.getArma()); return copia; }}
public class Inimigo { private String tipo; private Double vida; private Double dano; private Arma arma; // Arma é um objeto mutável com nome e bônus de dano
// getters e setters...}Responda:
- Por que essa forma de copiar campo a campo é um problema de design?
- Que tipo de bugs ou comportamentos estranhos podem acontecer se um novo campo for adicionado a
Inimigoe ocriarCopianão for atualizado? - Observe
copia.setArma(antigo.getArma()). O que acontece se o clone compartilhar a mesma instância deArmado original e o jogo modificar a arma de um deles? Qual conceito visto em aula isso ilustra (cópia rasa × profunda)?
Exercício 4: Exemplo real
Seção intitulada “Exercício 4: Exemplo real”Acesse os seguintes arquivos no projeto open source do JDK:
- Projeto: OpenJDK
- Arquivos:
Object.java(método nativoclone())Cloneable.java
O Java traz suporte a clonagem nativa: Object.clone() cria uma cópia do objeto, mas só funciona se a classe implementar a interface marcadora Cloneable. Diferente do padrão visto em aula, aqui a própria máquina virtual é quem faz a cópia.
Responda:
- Observe as exigências do
clone()nativo: retornaObject(exigindo cast), pode lançarCloneNotSupportedExceptione depende desuper.clone(). Compare esse mecanismo com o contrato de clonagem visto em aula (interface com métodoclonar()+ construtor de cópia). Qual é mais próximo da ideia do GoF de Prototype e por quê? - Vimos que a cópia rasa faz o clone compartilhar os objetos internos com o original. No
clone()nativo do Java, o comportamento padrão é a cópia rasa ou cópia profunda?
Exercício 5: Implementação
Seção intitulada “Exercício 5: Implementação”Imagine que você foi contratado para criar o sistema de inimigos de um jogo.
O jogo possui vários tipos de inimigo (guerreiro, mago, arqueiro, chefe), cada um com muita configuração (tipo, vida, dano e uma Arma). Como os inimigos nascem de uma base parecida e cada fase precisa de várias variações, recriar cada um com new repetiria muito código de construção.
Sua missão
Seção intitulada “Sua missão”Implemente, em Java, um sistema que crie inimigos por cópia de protótipos, usando o padrão Prototype.
- Crie a classe
Arma:- Campos, por exemplo,
nomeebonusDano, com getters e setters (objeto mutável). - Um método
clonar()que retorna uma novaArmaindependente (para a cópia profunda).
- Campos, por exemplo,
- Crie a interface
InimigoPrototype:- Contrato de clonagem:
InimigoPrototype clonar().
- Contrato de clonagem:
- Crie a classe
Inimigo implements InimigoPrototype:- Campos:
tipo,vida,danoeArma arma. - Um construtor de cópia (
Inimigo(Inimigo base)) que copia os atributos simples e faz a cópia profunda daArma(usandoarma.clonar()). - Um método
clonar()que retornanew Inimigo(this). - Getters e setters para ajustar variações após a cópia.
- Campos:
- Crie a classe
RegistroDePrototipos:- Um
Map<String, InimigoPrototype>que guarda os protótipos prontos ("guerreiro","mago","arqueiro","chefe"). - Um método, por exemplo,
getPrototipo(String nome), que retorna o clone do protótipo (nunca o próprio protótipo). - O cliente pede a cópia pelo nome, sem conhecer a classe concreta
Inimigo.
- Um
- Crie uma classe de teste, por exemplo
Main, que:- Obtenha inimigos via
RegistroDePrototipospelos nomes. - Crie um inimigo elite a partir do
"guerreiro"(por exemplo,setVida(...)esetDano(...)maiores) e mostre que o protótipo original não muda. - Prove que os clones são objetos distintos (por exemplo, comparando referências ou
hashCode()). - Demonstre a cópia profunda: modifique a
Armade um clone e mostre que aArmade outro clone (e do protótipo) permanece intacta. - Se quiser, mostre também o que aconteceria se a cópia da
Armafosse rasa (compartilhando a mesma instância).
- Obtenha inimigos via