Implementação do Padrão Visitor no Carrinho de Compras

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;
}

Tags: design-patterns visitor-pattern java cpp software-design

Publicado em 6-15 10:32 por Thomas