13. Visitor és proxy

Czirkos Zoltán · 2019.02.27.

#include <iostream>
#include <vector>
#include <cstdlib>

/* Alakzat osztályhierarchia */
class Visitor;

class Alakzat {
    public:
        virtual ~Alakzat() {}
        virtual void feldolgoz(Visitor & i) = 0;
        virtual Alakzat* masol() const = 0;
};

/* "Visitor" tervezési minta: egy alakzattal csinál valamit,
 * annak típusától függően. */
class Kor;
class Negyzet;
class Teglalap;

class Visitor {
  public:
    virtual void kor(Kor &) = 0;
    virtual void negyzet(Negyzet &) = 0;
    virtual void teglalap(Teglalap &) = 0;
    virtual ~Visitor() {}
};

/* Alakzat leszármazottak */
class Kor : public Alakzat {
    private:
        int r;
    public:
        Kor(int r) : r(r) {}
        int get_r() const { return r; }
        virtual void feldolgoz(Visitor & i) {
            i.kor(*this);
        }
        virtual Alakzat* masol() const {
            return new Kor(*this);
        }
};

class Negyzet : public Alakzat {
    private:
        int a;
    public:
        Negyzet(int a) : a(a) {}
        int get_a() const { return a; }
        virtual void feldolgoz(Visitor & i) {
            i.negyzet(*this);
        }
        virtual Alakzat* masol() const {
            return new Negyzet(*this);
        }
};

class Teglalap : public Alakzat {
    private:
        int a, b;
    public:
        Teglalap(int a, int b) : a(a), b(b) {}
        int get_a() const { return a; }
        int get_b() const { return b; }
        virtual void feldolgoz(Visitor & i) {
            i.teglalap(*this);
        }
        virtual Alakzat* masol() const {
            return new Teglalap(*this);
        }
};

/* Visitor leszármazottak */
class Szamlalo : public Visitor {
  private:
    int kor_db = 0;
    int negyzet_db = 0;
    int teglalap_db = 0;
  public:
    void kiir() {
        std::cout << "Kör: " << kor_db
                  << ", négyzet: " << negyzet_db
                  << ", téglalap: " << teglalap_db << std::endl;
    }

    void kor(Kor &) {
        kor_db += 1;
    }
    void negyzet(Negyzet &) {
        negyzet_db += 1;
    }
    void teglalap(Teglalap &) {
        teglalap_db += 1;
    }
};

/* kiírja egy rekord adatait */
class Kiiro : public Visitor {
  private:
  public:
    virtual void kor(Kor & k) {
        std::cout << "Kor " << k.get_r() << std::endl;
    }
    virtual void negyzet(Negyzet & n) {
        std::cout << "Negyzet " << n.get_a() << std::endl;
    }
    virtual void teglalap(Teglalap & t) {
        std::cout << "Teglalap " << t.get_a() << " " << t.get_b() << std::endl;
    }
};

/* Proxy: egy alakzat*-ot helyettesít, de úgy,
 * hogy amikor másolódik, akkor az alakzatot is másolja. */
class Proxy {
    private:
        Alakzat* a;
    public:
        Proxy(Alakzat* a = NULL) {
            this->a = a;
        }
        Proxy(Proxy const & d) {
            this->a = d.a->masol();
        }
        Proxy& operator=(Proxy const & d) {
            if (this != &d) {
                delete a;
                this->a = d.a->masol();
            }
            return *this;
        }
        ~Proxy() {
            delete a;
        }
        void feldolgoz(Visitor & i) {
            a->feldolgoz(i);
        }
};


int main() {
    std::vector<Proxy> rajz;
    rajz.push_back(new Kor(4));
    rajz.push_back(new Negyzet(5));
    rajz.push_back(new Teglalap(5, 7));
    rajz.push_back(new Teglalap(8, 9));
    rajz.push_back(new Kor(8));

    /* milyen alakzatok vannak? bejárás kiíróval */
    Kiiro k;
    for (size_t i = 0; i < rajz.size(); ++i)
        rajz[i].feldolgoz(k);

    /* milyen alakzatok vannak? bejárás számlálóval */
    Szamlalo sz;
    for (size_t i = 0; i < rajz.size(); ++i)
        rajz[i].feldolgoz(sz);
    sz.kiir();

    /* rajz másolása. mivel itt a proxy-k másoló konstruktora
     * hívódik, az meg másolja az alakzatot, az összes fenti
     * alakzatból új példány létrejön. */
    std::vector<Proxy> rajz_masolat;
    rajz_masolat = rajz;
    Szamlalo sz2;
    for (size_t i = 0; i < rajz.size(); ++i)
        rajz[i].feldolgoz(sz2);
    sz2.kiir();

    /* itt pedig nem kell for... delete rajz[i], mivel a
     * proxy-k destruktora intézik */
    return 0;
}