O padrão Visitor permite adicionar novas operações a uma estrutura de objetos sem modificar as classes desses objetos. Neste exemplo, estendemos um sistema de carrinho de compras para incluir um novo tipo de processador: o embalador, responsável por embalar os itens do carrinho.
Implementação em Java
A interface Item define o contrato para todos os itens no carrinho, exigindo um método aceitar que recebe um processador.
public interface Item {
void aceitar(Processador processador);
}
A classe concreta Maçã implementa Item.
public class Maça implements Item {
@Override
public void aceitar(Processador processador) {
processador.visitar(this);
}
}
A classe concreta Livro também implementa Item.
public class Livro implements Item {
@Override
public void aceitar(Processador processador) {
processador.visitar(this);
}
}
A classe CarrinhoCompras mantém uma coleção de itens e delega a operação de aceitação do processador para cada item contido nela.
import java.util.ArrayList;
import java.util.List;
public class CarrinhoCompras {
private final List<Item> itens = new ArrayList<>();
public void aceitar(Processador processador) {
for (Item item : itens) {
item.aceitar(processador);
}
}
public void adicionarItem(Item item) {
itens.add(item);
}
}
A classe abstrata Processador define a estrutura base para os diferentes processadores, com métodos abstratos para visitar cada tipo de item concreto.
public abstract class Processador {
protected String nome;
public void definirNome(String nome) {
this.nome = nome;
}
public abstract void visitar(Maça maca);
public abstract void visitar(Livro livro);
}
A classe Embalador é uma implementação concreta do processadro.
public class Embalador extends Processador {
@Override
public void visitar(Maça maca) {
System.out.println("O embalador " + nome + " está embalando as maçãs.");
}
@Override
public void visitar(Livro livro) {
System.out.println("O embalador " + nome + " está embalando o livro.");
}
}
A classe Caixa (exemplo de outro processador) realiza o cálculo do preço.
public class Caixa extends Processador {
@Override
public void visitar(Maça maca) {
System.out.println("O caixa " + nome + " está pesando a maçã e calculando o preço.");
}
@Override
public void visitar(Livro livro) {
System.out.println("O caixa " + nome + " está calculando o preço do livro.");
}
}
A classe principle demonstra a utilização do padrão.
public class Principal {
public static void main(String[] args) {
Item livro1 = new Livro();
Item livro2 = new Livro();
Item maca1 = new Maça();
CarrinhoCompras carrinho = new CarrinhoCompras();
carrinho.adicionarItem(livro1);
carrinho.adicionarItem(livro2);
carrinho.adicionarItem(maca1);
Processador embalador = new Embalador();
embalador.definirNome("João");
carrinho.aceitar(embalador);
}
}
Implementação em C++
#include <iostream>
#include <vector>
#include <string>
class Processador;
class Apple;
class Book;
class Item {
public:
virtual void aceitar(Processador* processador) = 0;
virtual ~Item() = default;
};
class Processador {
protected:
std::string nome_;
public:
void definirNome(const std::string& nome) {
nome_ = nome;
}
virtual void visitar(Apple* maca) {}
virtual void visitar(Book* livro) {}
virtual ~Processador() = default;
};
class Apple : public Item {
public:
void aceitar(Processador* processador) override {
processador->visitar(this);
}
};
class Book : public Item {
public:
void aceitar(Processador* processador) override {
processador->visitar(this);
}
};
class Embalador : public Processador {
public:
void visitar(Apple* maca) override {
std::cout << "O embalador " << nome_ << " está embalando as maçãs." << std::endl;
}
void visitar(Book* livro) override {
std::cout << "O embalador " << nome_ << " está embalando o livro." << std::endl;
}
};
class CarrinhoCompras {
private:
std::vector<Item*> itens_;
public:
void aceitar(Processador* processador) {
for (auto* item : itens_) {
item->aceitar(processador);
}
}
void adicionarItem(Item* item) {
itens_.push_back(item);
}
~CarrinhoCompras() {
for (auto* item : itens_) {
delete item;
}
}
};
int main() {
auto* carrinho = new CarrinhoCompras();
carrinho->adicionarItem(new Book());
carrinho->adicionarItem(new Book());
carrinho->adicionarItem(new Apple());
auto* embalador = new Embalador();
embalador->definirNome("Ana");
carrinho->aceitar(embalador);
delete embalador;
delete carrinho;
return 0;
}