O padrão Visitor permite adicionar novas operações a uma hierarquia de classes sem alterá-las. Neste exemplo, estendemos o cenário de carrinho de compras incluindo um novo visitante: o empacotador, responsável por embalar os itens do carrinho.
Diagrama de Classes
O diagrama a seguir ilustra a estrutura do padrão aplicada ao sistema:
Implementação em Java
Interface Product
public interface Item {
void accept(Visitor visitor);
}
Classes Concretas de Item
Apple (Maçã)
public class Apple implements Item {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
Book (Livro)
public class Book implements Item {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
Classe Abstrata Visitor
public abstract class Visitor {
protected String identifier;
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public abstract void visit(Apple apple);
public abstract void visit(Book book);
}
Implementações do Visitor
Customre (Cliente)
public class Customer extends Visitor {
@Override
public void visit(Apple apple) {
System.out.println("Cliente " + identifier + " seleciona maçã");
}
@Override
public void visit(Book book) {
System.out.println("Cliente " + identifier + " compra livro");
}
}
Packer (Empacotador)
public class Packer extends Visitor {
@Override
public void visit(Apple apple) {
System.out.println("Empacotador " + identifier + " embala maçã");
}
@Override
public void visit(Book book) {
System.out.println("Empacotador " + identifier + " embala livro");
}
}
Saler (Vendedor)
public class Saler extends Visitor {
@Override
public void visit(Apple apple) {
System.out.println("Vendedor " + identifier + " pesa e calcula preço da maçã");
}
@Override
public void visit(Book book) {
System.out.println("Vendedor " + identifier + " calcula preço do livro");
}
}
Classe ShoppingCart (Carrinho de Compras)
import java.util.ArrayList;
import java.util.List;
public class ShoppingCart {
private List<Item> items = new ArrayList<>();
public void accept(Visitor visitor) {
for (Item item : items) {
item.accept(visitor);
}
}
public void addItem(Item item) {
items.add(item);
}
public void removeItem(Item item) {
items.remove(item);
}
}
Classe Client (Teste)
public class Client {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
cart.addItem(new Apple());
cart.addItem(new Book());
Visitor seller = new Saler();
seller.setIdentifier("Ana");
System.out.println("--- Vendedor ---");
cart.accept(seller);
Visitor packer = new Packer();
packer.setIdentifier("Carlos");
System.out.println("--- Empacotador ---");
cart.accept(packer);
Visitor client = new Customer();
client.setIdentifier("Maria");
System.out.println("--- Cliente ---");
cart.accept(client);
}
}
Implementação em C++
#include <iostream>
#include <string>
#include <list>
using namespace std;
class Item;
class Book;
class Apple;
class Visitor {
protected:
string name;
public:
void setName(string n) { name = n; }
virtual void visit(Apple* apple) {}
virtual void visit(Book* book) {}
};
class Item {
public:
virtual void accept(Visitor* visitor) {}
};
class Apple : public Item {
public:
void accept(Visitor* visitor) override {
visitor->visit(this);
}
};
class Book : public Item {
public:
void accept(Visitor* visitor) override {
visitor->visit(this);
}
};
class Customer : public Visitor {
public:
void visit(Book* book) override {
cout << "Cliente " << name << " compra livro" << endl;
}
void visit(Apple* apple) override {
cout << "Cliente " << name << " seleciona maçã" << endl;
}
};
class Saler : public Visitor {
public:
void visit(Book* book) override {
cout << "Vendedor " << name << " calcula preço do livro" << endl;
}
void visit(Apple* apple) override {
cout << "Vendedor " << name << " pesa e calcula preço da maçã" << endl;
}
};
class Packer : public Visitor {
public:
void visit(Book* book) override {
cout << "Empacotador " << name << " embala livro" << endl;
}
void visit(Apple* apple) override {
cout << "Empacotador " << name << " embala maçã" << endl;
}
};
class ShoppingCart {
private:
list<Item*> items;
public:
void addItem(Item* item) { items.push_back(item); }
void removeItem(Item* item) { items.remove(item); }
void accept(Visitor* visitor) {
for (auto item : items) {
item->accept(visitor);
}
}
};
int main() {
ShoppingCart* cart = new ShoppingCart();
cart->addItem(new Apple());
cart->addItem(new Book());
Customer* customer = new Customer();
customer->setName("João");
Saler* saler = new Saler();
saler->setName("Pedro");
Packer* packer = new Packer();
packer->setName("Lucas");
cout << "--- Cliente ---" << endl;
cart->accept(customer);
cout << "--- Vendedor ---" << endl;
cart->accept(saler);
cout << "--- Empacotador ---" << endl;
cart->accept(packer);
return 0;
}