I never knew this kind of thing to use when using decorators. And I would think that if you need to do this, then you should not use decorators, especially since you deliberately "push the decorator beyond his intent."
I had a hit to do this, the code below. Basically, I create a thin layer around the SimplePizza object, which understands what decorators need, then decorators decorate it.
The main problem here is that in order to maintain order in the output, you will need to maintain relationships between decorators, which can quickly become a nightmare for maintenance.
#include <iostream> #include <queue> #include <sstream> struct name_part { std::string mName; int mPriority; name_part(const std::string& name, int priority) : mName(name) , mPriority(priority) { } }; bool operator<(const name_part& a, const name_part& b) { return (a.mPriority < b.mPriority); } std::string priority_queueToString(const std::priority_queue<name_part>& orig) { std::ostringstream oss; std::priority_queue<name_part> q(orig); while (!q.empty()) { oss << q.top().mName << " "; q.pop(); } return oss.str(); } struct SimplePizza { virtual std::string name() { return "pizza"; } }; struct SimplePizzaImplementer : SimplePizza { SimplePizza *mDecorated; SimplePizzaImplementer() : mDecorated(0) { } SimplePizzaImplementer(SimplePizza *decorated) : mDecorated(decorated) { } virtual std::string name() { return priority_queueToString(nameParts()); } virtual std::priority_queue<name_part> nameParts() { std::priority_queue<name_part> q; if (mDecorated) { q.push(name_part(mDecorated->name(), 0)); } return q; } }; struct MushroomDecorator : SimplePizzaImplementer { SimplePizzaImplementer *mDecorated; MushroomDecorator(SimplePizzaImplementer *decorated) : mDecorated(decorated) { } virtual std::string name() { return priority_queueToString(nameParts()); } virtual std::priority_queue<name_part> nameParts() { std::priority_queue<name_part> q = mDecorated->nameParts(); q.push(name_part("mushroom", 1)); return q; } }; struct BigDecorator : SimplePizzaImplementer { SimplePizzaImplementer *mDecorated; BigDecorator(SimplePizzaImplementer *decorated) : mDecorated(decorated) { } virtual std::string name() { return priority_queueToString(nameParts()); } virtual std::priority_queue<name_part> nameParts() { std::priority_queue<name_part> q = mDecorated->nameParts(); q.push(name_part("big", 2)); return q; } }; int main() { SimplePizzaImplementer *impl = new SimplePizzaImplementer(new SimplePizza()); SimplePizza *pizza1 = new MushroomDecorator(new BigDecorator(impl)); SimplePizza *pizza2 = new BigDecorator(new MushroomDecorator(impl)); std::cout << pizza1->name() << std::endl; std::cout << pizza2->name() << std::endl; }
source share