//Simple demo of visitor pattern
//Uses raw poitner instead of smartpointers for demo purpose only
#include <iostream>
#include <string>
#include <map>
using namespace std;
class Visitor;
struct Item // items in inventory
{
virtual Item* clone() const=0; // duplicate an item for sotring in inventory
virtual int code() const=0; // code for the map
virtual void acceptVisitor(Visitor &v)=0; // allow for visitors
virtual ~Item() {}
};
class Book : public Item // a concrete item
{
int isbn; // with its specific data (a dvd has no isbn)
string name;
public:
Book() = default;
Book(const Book& b) = default;
Book(int isbn, const string &name);
int code() const override ; // implement item members
Item* clone() const override ;
void acceptVisitor(Visitor &v) override;
int getIsbn() const ; // provide getters to ensure encapsulation
const string& getTitle() const ;
};
class Inventory
{
private:
map<int, Item *> items;
public:
void addItem(const Item& i);
void acceptVisitor(Visitor &v);
};
class Visitor { // generic visitor. Can be used for report, for saving data, etc..
public:
virtual void visitInventory(Inventory *iv) = 0;
virtual void visitBook(Book*) = 0;
//... if you have new type of items, just add a function here
virtual void visitEnd() {};
};
class Report : public Visitor // FIrst report: just tell what to do fpor every class you use
{
private:
Inventory* i;
int count=0;
public:
Report(Inventory& i);
void visitInventory(Inventory *iv);
void visitBook(Book*b);
void visitEnd(); // to end the report
};
Book::Book(int isbn, const string &name) : isbn(isbn), name(name) {}
int Book::code() const { return isbn; }
Item* Book::clone() const { return new Book(*this); }
void Book::acceptVisitor(Visitor &v) { v.visitBook(this); }
int Book::getIsbn() const { return(isbn); }
const string& Book::getTitle() const { return (name); }
void Inventory::addItem(const Item& i)
{
items[i.code()] =i.clone();
}
void Inventory::acceptVisitor(Visitor &v) {
v.visitInventory(this);
for (auto &x : items)
x.second->acceptVisitor(v);
v.visitEnd();
}
Report::Report(Inventory& i) : i(&i),count(0)
{ i.acceptVisitor(*this); }
void Report::visitInventory(Inventory *iv) {
cout << "Nice report:"<<endl;
cout << "============"<<endl;
}
void Report::visitBook(Book*b) {
cout << "Book: "<< b->getTitle() << " (ISBN "<<b->getIsbn()<<" )"<<endl;
count++;
}
void Report::visitEnd() {
cout << "Total of "<<count<<" items"<<endl;
}
int main() // CORRECT: never main(void) !!!!
{
Inventory i;
i.addItem(Book(1234, "Foo Bar I"));
i.addItem(Book(4567, "Foo Bar II"));
Report r(i);
return 0;
}