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