Wzorce projektowe (19)

Autor: Damian Chodorek • Opublikowany: 24 lipca 2015 • Kategoria: kursy, wzorce projektowe

Wizytator.

Jest to wzorzec obiektowy. Jego celem jest odseparowanie nowych operacji od aktualnych struktur bez konieczności ich modyfikacji.

Klasy

class Visitor{/*
abstrakcyjna klasa zawierająca deklarację wirtualnych metod odpowiadających za wizytację poszczególnych typów obiektów odwiedzanych
*/};

class ConcreteVisitor: public Visitor{/*
definiuje konkretny sposób działania metod odwiedzających, przeważnie takich klas jest kilka i odpowiadają za różne czynności, np. jeden wizytator wypisuje, inny zlicza
*/};

class Visitable{/*
abstrakcyjna klasa, po której dziedziczą wszystkie elementy struktury, które będą odwiedzane przez wizytatora;
deklaruje wirtualną metodę accept(Visitor* v), która wywołuje v->visit(this)
*/};

class ConcreteVisitable: public Visitable{/*
klasa konkretnych obiektów struktury (liści)
*/};

class ObjectStructure: public Visitable{/*
struktura liści, może być drzewo lub lista; powinna zawierać mechanizm do przechodzenia po jej elementach;
jej metoda accept(Visitor* v) wywołuje metodę accept(v) jej elementów
*/};

Etapy działania

  1. Klient tworzy strukturę elementów.
  2. Dla każdego jej elementu wywołujemy metodę accept() przekazując do niej konkretnego wizytatora.

Konsekwencje

  • powinien być używany tam gdzie nie zmienia się struktura elementów, ale zmieniają się operacje, które na nich
    wykonujemy,
  • wizytator jest zależny od odwiedzanego, ale nie na odwrót.

Przykład

#include <iostream>
#include <vector>
using namespace std;

class Bread;
class Beer;
class MultiPack;

///abstrakcyjny Visitor
class Visitor
{
    public:
        virtual void visit(Bread&) = 0;
        virtual void visit(Beer&) = 0;
        virtual void visit(MultiPack&) = 0;
};

//abstrakcyjny Visitable
class Product
{
    public:
        virtual void accept(Visitor& w)=0;

        double getPrice() { 
            return price;
        }

    protected:    
        Product(double gprice) : price(gprice) {}

    private:
        double price;
};

///concrete visitable
class Bread : public Product
{
    public:
        Bread(double gprice, double gweight) : Product(gprice),
            weight(gweight)
        {
        }
        
        double getWeigth()
        {
            return weight;
        }
        
        void accept(Visitor& w)
        {
          w.visit(*this);
        }

    private:
        double weight;
};


class Beer: public Product
{
    public:
        Beer(double gprice, double gsize) : Product(gprice),
            size(gsize)
        {
        }
        
        double getSize()
        {
            return size;
        }

        void accept(Visitor& w)
        {
          w.visit(*this);
        }

    private:
        double size;
};

///klasa Structure
class MultiPack: public Product
{
    public:
        MultiPack(double gprice, int gquantity) : Product(0),
            quantity(gquantity)
        {
            for(int i=1; i<= gquantity; i++)
                wec.push_back(Beer(gprice/gquantity,500));
        }

        void accept(Visitor& w)
        {    
            w.visit(*this);
            for(vector<Beer>::iterator i = wec.begin(); i != wec.end(); i++)       
                w.visit(*i);
        }

        int getQuantity()
        {
            return quantity;
        }

    private:
        vector<Beer> wec;
        int quantity;
};

///konkretny wizytator
class Show : public Visitor
{
    public:
        virtual void visit(Bread& c)
        {
            cout << "+ Chleb o wadze " << c.getWeigth() <<
              " gramow  w cenie " << c.getPrice() << " zl" <<  endl;
        }
 
        virtual void visit(Beer& p)
        {
            cout << "+ Piwo w puszce o wielkosci " <<
               p.getSize() << " mililitrow w cenie " << p.getPrice() << " zl" << endl;
        }
    
        void visit(MultiPack& w)
        {
            cout << "+ Wielopak zawierajacy " <<
                w.getQuantity() << " nastepujacych artykulow: " << endl;
        }
};


class Count : public Visitor
{
    public:
        Count(){ sum = 0; }
        void visit(Bread& c)
        {
            sum += c.getPrice();
        }

        void visit(Beer& p)
        {
            sum += p.getPrice();
        }

        void visit(MultiPack& w)
        {
        ///wielopak nic nie kosztuje, cena rozłożona jest na produkty
        }

        double getSum()
        {
            return sum;
        }

    private:
        double sum;
};

int main()
{
    //utworzenie 'listy zakupów'
    vector<Product*> shopping;

    ///utworzenie pojedynczych produktów
    Bread c1(2.5,500);
    Beer p1(2.9,600);
    MultiPack w1(10,4);

    ///dodanie ich do listy    
    shopping.push_back(&c1);
    shopping.push_back(&p1);
    shopping.push_back(&w1);

    // Obiekty wizytator zliczania wartoćci i wypisywania
    Count zl;
    Show wp;

    // Wypisanie listy zakupów przy użyciu wizytatora wypisywania
    cout << "Lista zakupow: " << endl;
    for(vector<Product*>::iterator i = shopping.begin(); i != shopping.end(); i++)
        (*i)->accept(wp);

    // Zliczenie sumarycznej wartości produktów koszyka przy użyciu wizytatora zliczania
    for(vector<Product*>::iterator i = shopping.begin(); i != shopping.end(); i++)
        (*i)->accept(zl);

    cout << "Sumaryczna wartosc produktow to: " << zl.getSum() << "zl"
         << endl;


    return 0;
}

część 20

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.