Padrões de Projetos - Prototype

De Aulas


Afluentes: Modelos, métodos e técnicas da engenharia de software

Definição

Padrão criacional para criar novos objetos a partir de uma instância existente (protótipo), em vez de criar novos objetos do zero, fazendo uma cópia do objeto existente.

Objetivo

Permitir a criação de novos objetos com as mesmas características de um objeto existente, o que pode ser útil quando o processo de criação de novos objetos é custoso ou complexo.

Componentes principais

  • Prototype: Define a interface para clonar o objeto. Esta interface geralmente inclui um método clone() ou similar.
  • Prototype Concreto: Implementa o método clone(), realizando a clonagem real do objeto.
  • Cliente: Usa o método clone() para criar uma nova instância do objeto sem usar o construtor diretamente.

Quando usar o Prototype

  • Quando a criação de novos objetos é cara (por exemplo, envolve muitas operações computacionais ou inicializações complexas).
  • Quando você deseja evitar subclasses de um objeto e criar novos objetos de forma dinâmica em tempo de execução.
  • Quando deseja manter o estado de um objeto existente ao criar novas instâncias.

Exemplo em Java

Vamos supor que estamos criando uma interface de protótipo para um sistema que manipula inimigos em um jogo de computador.

1 - Criamos uma interface Prototype com o método clone()

// Interface Prototype com o método clone
interface Prototype {
    Prototype clone(); // Método para clonar o objeto
}

2 - Criamos classes concretas que implementam a interface Prototype

public class Enemy implements Prototype {
    private int id; // id do inimigo no jogo
    private int x; // posição x do inimigo
    private int y; // posição y do inimigo
    private int xp; // pontos de experiência
    private int hp; // pontos de vida

    private static int counter = 0;

    public Enemy(int x, int y, int xp, int hp) {
        this.id = Enemy.counter++;
        this.x = x;
        this.y = y;
        this.xp = xp;
        this.hp = hp;
    }

    @Override
    public Prototype clone() {
        // Clona o objeto atual
        return new Enemy(x, y, xp, hp);
    }

    public void draw() {
        System.out.println("Enemy " + id + " at (" + x + ", " + y + "): XP: " + xp + ", HP:" + hp);
    }

}

3 - O cliente usa essas classes para criar novos objetos clonando os existentes

public class Main {
    public static void main(String[] args) {
        // Criando um objeto do tipo Enemy
        Enemy originalEnemy = new Enemy(100, 200, 34, 100);
        originalEnemy.draw();

        // Clonando o Enemy
        Enemy clonedEnemy = (Enemy) originalEnemy.clone();
        clonedEnemy.draw();
    }
}

Explicação

  • Interface Prototype: Define o método clone() que será implementado pelas classes concretas para realizar a clonagem.
  • Classe Enemy: Implementa o método clone(), criando um novo objeto Enemy com os mesmos valores na posição x e y e com pontos de experiência (xp) e pontos de vida (100%).
    • Mas veja que o id do inimigo deve ser único no jogo, então ele é gerado quando criamos o objeto autoincrementando a partir do último id gerado.
  • Cliente (Main): Cria objeto Enemy, e depois usa o método clone() para duplicá-lo.

Vantagens

  • Clonagem de objetos complexos: É útil quando os objetos têm uma estrutura complexa ou quando a criação de novos objetos envolve processos dispendiosos.
  • Independência da implementação: O padrão permite clonar objetos sem se preocupar com a implementação detalhada da classe.
  • Redução de dependência: Evita a necessidade de dependência direta de construtores, permitindo criar novos objetos dinamicamente.

Desvantagens

  • Clonagem profunda vs. Clonagem rasa: A implementação do clone pode se tornar complicada, especialmente se o objeto contiver referências para outros objetos. Nesse caso, é preciso garantir que a clonagem seja "profunda" (deep copy) em vez de "rasa" (shallow copy).
  • Manutenção: Manter o código de clonagem pode ser complexo, especialmente com classes que contêm muitos atributos.

Clonagem rasa vs. Clonagem profunda

  • Clonagem rasa (shallow copy): Copia apenas as referências dos objetos (ou seja, os atributos que são objetos ainda apontam para os mesmos objetos na memória).
  • Clonagem profunda (deep copy): Copia os valores dos objetos e também cria cópias independentes de quaisquer objetos referenciados.

No Java, o método clone() vem da classe base Object e por padrão faz uma clonagem rasa. Se você quiser uma clonagem profunda, precisará sobrescrever esse comportamento de forma adequada.

Resumo

O Prototype é um padrão criacional que permite criar novos objetos clonando um protótipo existente. Ele é útil quando a criação de novos objetos é custosa ou quando você deseja evitar a criação de subclasses adicionais, promovendo a reutilização de objetos pré-existentes através de clonagem.