When a Wizard casts the Monster Summoning spell, all of the summoned monsters shall follow his command.  Should the Wizard interact with his summoned monsters directly (what are the potential pitfalls in this case?) or indirectly through a mediator?In my code below, I'm using a mediator, but since such a specialized mediator (used only for this spell) do not pertain to all living beings (most living beings cannot even cast spells), I've placed the mediator data member only within a specific State class that is only created when the spell is cast.  Here I have the mediator registering the summoned monsters when the spell is cast, dispatching the commands from the wizard to the summoned monsters, unregistering a summoned monster when it dies, and destroying all the summoned monsters in the event that the wizard himself dies (or loses his concentration).Note: all classes are structs here for simplicity.#include <iostream>#include <list>#include <string>struct Mediator {    struct LivingBeing* being;    Mediator (LivingBeing* b) : being(b) {}};struct MonsterSummoningMediator : Mediator {    std::list<struct SummonedMonster*> summonedMonsters;    using Mediator::Mediator;    ~MonsterSummoningMediator() {destroySummonedMonsters();}    void registerSummonedMonster (SummonedMonster* m) {summonedMonsters.emplace_back(m);}    void unregisterSummonedMonster (SummonedMonster* m) {summonedMonsters.remove(m);}    inline void distributeAttackCommand();    inline void distributeShieldMeCommand();    inline void destroySummonedMonsters();};struct State {    LivingBeing* being;    State (LivingBeing* b) : being(b) {}    virtual ~State() = default;};struct MonsterSummonerState : State {    MonsterSummoningMediator* mediator;    MonsterSummonerState (LivingBeing* being) :        State(being), mediator(new MonsterSummoningMediator(being)) {}    ~MonsterSummonerState() {delete mediator;}    void addSummonedMonster(SummonedMonster* m) {mediator->registerSummonedMonster(m);}};struct LivingBeing {    std::string name;    State* state;    LivingBeing() = default;    LivingBeing (const std::string& n) : name(n) {}    virtual ~LivingBeing() = default;    virtual void dies() {std::cout << \n << name <<  dies.\n;}};struct Monster : LivingBeing {    using LivingBeing::LivingBeing;    virtual ~Monster() {std::cout << name <<  destroyed.\n;}};struct SummonedMonster {    Monster* monster;    LivingBeing* summoner;    SummonedMonster (Monster* m, LivingBeing* s) : monster(m), summoner(s) {}    ~SummonedMonster() {delete monster;}    void receiveAttackCommand() {        std::cout << monster->name <<  will follow  << summoner->name << 's order to attack.\n;    }    void receiveShieldMeCommand() {        std::cout << monster->name <<  will follow  << summoner->name << 's order to shield him.\n;    }};struct Wizard : LivingBeing {    using LivingBeing::LivingBeing;    void castsMonsterSummoning() {        state = new MonsterSummonerState(this);        MonsterSummonerState* monsterSummonerState = dynamic_cast<MonsterSummonerState*>(state);        for (int i = 0; i < 5; i++) {            Monster* monster = new Monster(Summoned Goblin);            monsterSummonerState->addSummonedMonster(new SummonedMonster(monster, this));        }        std::cout << Wizard::castsMonsterSummoning() called by  << name << .\n;    }    // The MonsterSummoningMediator passes the order to all the summoned monsters.    // There is no direct interaction between the summoner and the summoned monsters.    void orderSummonedMonstersToAttack() {        dynamic_cast<MonsterSummonerState*>(state)->mediator->distributeAttackCommand();    }    void orderSummonedMonstersToShieldMe() {        dynamic_cast<MonsterSummonerState*>(state)->mediator->distributeShieldMeCommand();    }    virtual void dies() override {        LivingBeing::dies();        if (dynamic_cast<MonsterSummonerState*>(state))  // if (isAMonsterSummoner())            endMonsterSummoningSpell();    }    void endMonsterSummoningSpell() {        std::cout << \n << name << 's Monster Summoning spell has ended.\n;        delete state;        state = new State(this);    }};inline void MonsterSummoningMediator::distributeAttackCommand() {    for (SummonedMonster* x : summonedMonsters)        x->receiveAttackCommand();}inline void MonsterSummoningMediator::distributeShieldMeCommand() {    for (SummonedMonster* x : summonedMonsters)        x->receiveShieldMeCommand();}inline void MonsterSummoningMediator::destroySummonedMonsters() {    for (SummonedMonster* x : summonedMonsters)        delete x;    summonedMonsters.clear();}int main() {    Wizard wizard(Merlin);    wizard.castsMonsterSummoning();    wizard.orderSummonedMonstersToAttack();    wizard.orderSummonedMonstersToShieldMe();    wizard.dies();}Output:Wizard::castsMonsterSummoning() called by Merlin.Summoned Goblin will follow Merlin's order to attack.Summoned Goblin will follow Merlin's order to attack.Summoned Goblin will follow Merlin's order to attack.Summoned Goblin will follow Merlin's order to attack.Summoned Goblin will follow Merlin's order to attack.Summoned Goblin will follow Merlin's order to shield him.Summoned Goblin will follow Merlin's order to shield him.Summoned Goblin will follow Merlin's order to shield him.Summoned Goblin will follow Merlin's order to shield him.Summoned Goblin will follow Merlin's order to shield him.Merlin dies.Merlin's Monster Summoning spell has ended.Summoned Goblin destroyed.Summoned Goblin destroyed.Summoned Goblin destroyed.Summoned Goblin destroyed.Summoned Goblin destroyed.So far, the wizard and his summoned monsters are unaware of each other in the code.  But direct interaction will occur between them and the wizard's enemies when they fight each other (this is shown below).  Yet the summoned monsters are not really monsters--they are temporary illusions that can cause damage, so I'm confused about what the design should really be.Should the proxy class SummonedMonster even be used at all?  That's another issue I have.  The reason for SummonedMonster is that it holds the data member SummonedMonster::summoner, which should not be in Monster (since not all monsters are summoned).  But SummonedMonster::name has no value.  Only SummonedMonster::monster->name has the desired value.  Though I could define SummonedMonster::getName() const {return monster->name;}, I will have to do this for all data members of Monster.  Should I instead define a State derived class SummonedMonsterState instead?Here is an extended code illustrating the problems I've mentioned:#include <iostream>#include <list>#include <string>struct LivingBeing;std::list<LivingBeing*> allBeingsPresent;struct Mediator {    LivingBeing* being;    Mediator (LivingBeing* b) : being(b) {}};struct MonsterSummoningMediator : Mediator {    std::list<struct SummonedMonster*> summonedMonsters;    using Mediator::Mediator;    ~MonsterSummoningMediator() {destroySummonedMonsters();}    void registerSummonedMonster (SummonedMonster* monster) {summonedMonsters.emplace_back(monster);}    void unregisterSummonedMonster (SummonedMonster* monster) {summonedMonsters.remove(monster);}    inline void distributeAttackCommand();    inline void distributeShieldMeCommand();    inline void destroySummonedMonsters();};struct State {    LivingBeing* being;    State (LivingBeing* b) : being(b) {}    virtual ~State() = default;};struct MonsterSummonerState : State {    MonsterSummoningMediator* mediator;    MonsterSummonerState (LivingBeing* being) :         State(being), mediator(new MonsterSummoningMediator(being)) {}    ~MonsterSummonerState() {delete mediator;}};struct LivingBeing {    std::string name;    State* state;    LivingBeing() = default;    LivingBeing (const std::string& n) : name(n) {allBeingsPresent.emplace_back(this);}    virtual ~LivingBeing() = default;    virtual void dies() {std::cout << \n << name <<  dies.\n;}    void attacks (LivingBeing* target) {        std::cout << \n << name <<  attacks  << target->name << .\n;        target->dies();    }};struct Monster : LivingBeing {    using LivingBeing::LivingBeing;    virtual ~Monster() {std::cout << name <<  destroyed.\n;}};struct SummonedMonster : Monster {    Monster* monster;  // Proxy Pattern    LivingBeing* summoner;    SummonedMonster (Monster* m, LivingBeing* s) : monster(m), summoner(s) {        allBeingsPresent.emplace_back(this);    }    ~SummonedMonster() {delete monster;}    void receiveAttackCommand() {std::cout << monster->name <<  will follow  << summoner->name << 's order to attack.\n;}    void receiveShieldMeCommand() {std::cout << monster->name <<  will follow  << summoner->name << 's order to shield him.\n;}    virtual inline void dies() override;};struct CharacterClass : LivingBeing {    using LivingBeing::LivingBeing;};struct Fighter : CharacterClass {    using CharacterClass::CharacterClass;};struct Wizard : CharacterClass {    using CharacterClass::CharacterClass;    void castsMonsterSummoning() {        state = new MonsterSummonerState(this);        MonsterSummoningMediator* monsterSummoningMediator = getMonsterSummoningMediator();        for (int i = 0; i < 5; i++) {            Monster* monster = new Monster(Summoned Goblin);            monsterSummoningMediator->registerSummonedMonster(new SummonedMonster(monster, this));            allBeingsPresent.remove(monster);  // Since only the new SummonedMonster* is to be inserted into allBeingsPresent.        }    }    MonsterSummoningMediator* getMonsterSummoningMediator() const {        return dynamic_cast<MonsterSummonerState*>(state)->mediator;    }    void orderSummonedMonstersToAttack() {        getMonsterSummoningMediator()->distributeAttackCommand();    }    void orderSummonedMonstersToShieldMe() {        getMonsterSummoningMediator()->distributeShieldMeCommand();    }    virtual void dies() override {        LivingBeing::dies();        if (dynamic_cast<MonsterSummonerState*>(state))  // if (isAMonsterSummoner())            endMonsterSummoningSpell();    }    void endMonsterSummoningSpell() {        std::cout << \n << name << 's Monster Summoning spell has ended.\n;        delete state;        state = new State(this);    }};inline void SummonedMonster::dies() {    std::cout << \n << monster->name <<  dies.\n;  // Mediator now unregisters 'this'.    dynamic_cast<Wizard*>(summoner)->getMonsterSummoningMediator()->unregisterSummonedMonster(this);}inline void MonsterSummoningMediator::distributeAttackCommand() {    for (SummonedMonster* x : summonedMonsters)        x->receiveAttackCommand();}inline void MonsterSummoningMediator::distributeShieldMeCommand() {    for (SummonedMonster* x : summonedMonsters)        x->receiveShieldMeCommand();}inline void MonsterSummoningMediator::destroySummonedMonsters() {    for (SummonedMonster* x : summonedMonsters)        delete x;    summonedMonsters.clear();}int main() {    Wizard wizard(Merlin);    Fighter fighter(Borg);    wizard.castsMonsterSummoning();    for (LivingBeing* x : allBeingsPresent) std::cout << x->name <<  is present.\n;    wizard.orderSummonedMonstersToAttack();    wizard.orderSummonedMonstersToShieldMe();    fighter.attacks(allBeingsPresent.back());  // The summoned monster dies.    wizard.dies();}Output:Merlin is present.Borg is present. is present.  // name value of the summoned monster missing is present.  // and thus all other data member values missing. is present. is present. is present.Summoned Goblin will follow Merlin's order to attack.Summoned Goblin will follow Merlin's order to attack.Summoned Goblin will follow Merlin's order to attack.Summoned Goblin will follow Merlin's order to attack.Summoned Goblin will follow Merlin's order to attack.Summoned Goblin will follow Merlin's order to shield him.Summoned Goblin will follow Merlin's order to shield him.Summoned Goblin will follow Merlin's order to shield him.Summoned Goblin will follow Merlin's order to shield him.Summoned Goblin will follow Merlin's order to shield him.Borg attacks .  // name value of the summoned monster missingSummoned Goblin dies.Merlin dies.Merlin's Monster Summoning spell has ended.Summoned Goblin destroyed. destroyed.Summoned Goblin destroyed. destroyed.Summoned Goblin destroyed. destroyed.Summoned Goblin destroyed. destroyed.
Use of Mediator Pattern or Proxy Pattern for a game
c++;game;c++11;proxy;mediator
The flaws of using the proxy pattern demonstrated above will be removed if I use the adapter pattern instead:struct LivingBeing {    struct SummonedTag {};    std::string name;    State* state;    LivingBeing() = default;    LivingBeing (const std::string& n) : name(n) {allBeingsPresent.emplace_back(this);}    LivingBeing (const std::string& n, SummonedTag) : name(n) {}  // Do NOT call 'allBeingsPresent.emplace_back(this);' else there will be duplication.    // ...};struct Monster : LivingBeing {    using LivingBeing::LivingBeing;    // ...};struct Goblin : Monster { using Monster::Monster; };struct SummonedMonster : Monster {    LivingBeing* summoner;    SummonedMonster (LivingBeing* s, const std::string& name) : Monster(name), summoner(s) {}    // ...}template <typename T>struct Summoned : SummonedMonster, T {  // *** Adapter Pattern    Summoned (LivingBeing* summoner, const std::string& name) : SummonedMonster(summoner, name),        T(name, SummonedTag{}) {}};template <typename T>void Wizard::castsMonsterSummoning() {        state = new MonsterSummonerState(this);        MonsterSummoningMediator* monsterSummoningMediator = getMonsterSummoningMediator();        for (int i = 0; i < 5; i++)            monsterSummoningMediator->registerSummonedMonster(new Summoned<T>(this, Summoned Monster));    }}The resulting output does not show the problems in the question's output:Wizard::castsMonsterSummoning() called by Merlin.monsterSummoningMediator->summonedMonsters.size() = 5Merlin is present.Borg is present.Summoned Monster is present.Summoned Monster is present.Summoned Monster is present.Summoned Monster is present.Summoned Monster is present.Summoned Monster will follow Merlin's order to attack.Summoned Monster will follow Merlin's order to attack.Summoned Monster will follow Merlin's order to attack.Summoned Monster will follow Merlin's order to attack.Summoned Monster will follow Merlin's order to attack.Summoned Monster will follow Merlin's order to shield him.Summoned Monster will follow Merlin's order to shield him.Summoned Monster will follow Merlin's order to shield him.Summoned Monster will follow Merlin's order to shield him.Summoned Monster will follow Merlin's order to shield him.Borg attacks Summoned Monster.Summoned Monster dies.Merlin dies.Merlin's Monster Summoning spell has ended.MonsterSummoningMediator destroyed.Summoned Monster destroyed.Summoned Monster destroyed.Summoned Monster destroyed.Summoned Monster destroyed.Summoned Monster destroyed.  // Hmmm... duplicate destructor call (seems harmless though).Summoned Monster destroyed.Summoned Monster destroyed.Summoned Monster destroyed.I still have to investigate if this works in more complex constructions though.Update:  I've experimented this new design with more complex constructions and its seems to be working fine.  Here is my latest design, in case you wanted to see the whole thing:#include <iostream>#include <list>#include <string>struct LivingBeing;std::list<LivingBeing*> allBeingsPresent;struct Mediator {    LivingBeing* being;    Mediator (LivingBeing* b) : being(b) {}};struct MonsterSummoningMediator : Mediator {    std::list<struct SummonedMonster*> summonedMonsters;    using Mediator::Mediator;    ~MonsterSummoningMediator() {std::cout << MonsterSummoningMediator destroyed.\n;  destroySummonedMonsters();}    void registerSummonedMonster (SummonedMonster* monster) {summonedMonsters.emplace_back(monster);}    void unregisterSummonedMonster (SummonedMonster* monster) {        summonedMonsters.remove(monster);        std::cout << MonsterSummoningMediator::unregisterSummonedMonster called.\n;    }    inline void distributeAttackCommand();    inline void distributeShieldMeCommand();    inline void destroySummonedMonsters();};struct State {    LivingBeing* being;    State (LivingBeing* b) : being(b) {}    virtual ~State() = default;};struct MonsterSummonerState : State {    MonsterSummoningMediator* mediator;    MonsterSummonerState (LivingBeing* being) : State(being), mediator(new MonsterSummoningMediator(being)) {}    ~MonsterSummonerState() {delete mediator;}};struct LivingBeing {    struct Data {        std::string name;        int hitPoints, strength;    };    struct SummonedTag {};    std::string name;    int hitPoints, strength;    State* state;    LivingBeing() = default;    LivingBeing (const Data& data) : name(data.name), hitPoints(data.hitPoints), strength(data.strength) {allBeingsPresent.emplace_back(this);}    LivingBeing (const Data& data, SummonedTag) : name(data.name), hitPoints(data.hitPoints), strength(data.strength) {}  // Do NOT call 'allBeingsPresent.emplace_back(this);' else there will be duplication.    virtual ~LivingBeing() = default;    void losesHitPoints (int loss) {const int formerHitPoints = hitPoints;  hitPoints -= loss;  std::cout << name <<  has gone from  << formerHitPoints <<  hit points to  << hitPoints <<  hit points. << std::endl;}    virtual void dies() {std::cout << \n << name <<  dies.\n;}    void attacks (LivingBeing* target) {std::cout << \n << name <<  attacks  << target->name << .\n;  target->losesHitPoints(20);  target->dies();}};struct Monster : LivingBeing {    using LivingBeing::LivingBeing;    virtual ~Monster() {std::cout << name <<  destroyed.\n;}};struct Goblin : Monster { using Monster::Monster; };struct Spell {    std::string name;    Spell (const std::string& n) : name(n) {}} *CharmPerson = new Spell(Charm Person), *Haste = new Spell(Haste), *SleepSpell = new Spell(Sleep);struct GoblinWizard : Goblin {    std::list<Spell*> spellsKnown;    std::string specialty;    int numWands;    template <typename... Args>    GoblinWizard (const LivingBeing::Data& data, const std::list<Spell*>& spells, const std::string s, int num, Args&&... args) :        Goblin(data, std::forward<Args>(args)...), spellsKnown(spells), specialty(s), numWands(num) {}};struct Lich : Monster {    struct Data {        std::list<Spell*> spellsKnown;        int undeadLevel;        std::string deity;    };    Data lichData;    template <typename... Args>    Lich (const LivingBeing::Data& data, const Data& lData, Args&&... args) : Monster(data, std::forward<Args>(args)...), lichData(lData) {}};struct SummonedMonster : Monster {    LivingBeing* summoner;    SummonedMonster (LivingBeing* s, const LivingBeing::Data& data) : Monster(data, SummonedTag{}), summoner(s) {}    void receiveAttackCommand() {std::cout << name <<  (hit points =  << hitPoints << , strength =  << strength << ) will follow  << summoner->name << 's order to attack.\n;}    void receiveShieldMeCommand() {std::cout << name <<  (hit points =  << hitPoints << , strength =  << strength << ) will follow  << summoner->name << 's order to shield him.\n;}    virtual inline void dies() override;};template <typename T>struct Summoned : SummonedMonster, T {  // Adapter Pattern    template <typename... Args>    Summoned (LivingBeing* summoner, const LivingBeing::Data& data, Args&&... args) : SummonedMonster(summoner, data), T(data, std::forward<Args>(args)..., SummonedTag{}) {        allBeingsPresent.emplace_back(dynamic_cast<SummonedMonster*>(this));  // This is the pointer that we want to insert into allBeingsPresent.    }};struct CharacterClass : LivingBeing {    using LivingBeing::LivingBeing;};struct Fighter : CharacterClass {    using CharacterClass::CharacterClass;};struct Wizard : CharacterClass {    using CharacterClass::CharacterClass;    void castsMonsterSummoning() {        state = new MonsterSummonerState(this);        MonsterSummoningMediator* monsterSummoningMediator = getMonsterSummoningMediator();        for (int i = 0; i < 5; i++) {            monsterSummoningMediator->registerSummonedMonster(new Summoned<Goblin>                (this, {Summoned Goblin, 6 + i, 11 + i}));            monsterSummoningMediator->registerSummonedMonster(new Summoned<GoblinWizard>                (this, {Summoned Goblin Wizard, 7 + i, 12 + i}, std::list<Spell*>{CharmPerson, Haste, SleepSpell}, Illusion, 8));  // 'std::list<Spell*>' required in order for the compiler to deduce the what Args... is.            monsterSummoningMediator->registerSummonedMonster(new Summoned<Lich>                (this, {Summoned Lich, 8 + i, 13 + i}, Lich::Data{{Haste, SleepSpell, CharmPerson}, 7, Demogorgon}));  // 'Lich::Data' required in order for the compiler to deduce the what Args... is.        }        std::cout << Wizard::castsMonsterSummoning() called by  << name << .\n;    }    MonsterSummoningMediator* getMonsterSummoningMediator() const {return dynamic_cast<MonsterSummonerState*>(state)->mediator;}    void orderSummonedMonstersToAttack() {        getMonsterSummoningMediator()->distributeAttackCommand();    }    void orderSummonedMonstersToShieldMe() {        getMonsterSummoningMediator()->distributeShieldMeCommand();    }    virtual void dies() override {        LivingBeing::dies();        if (dynamic_cast<MonsterSummonerState*>(state))            endMonsterSummoningSpell();    }    void endMonsterSummoningSpell() {        std::cout << \n << name << 's Monster Summoning spell has ended.\n;        delete state;        state = new State(this);    }};inline void SummonedMonster::dies() {    std::cout << \n << name <<  dies.\n;    dynamic_cast<Wizard*>(summoner)->getMonsterSummoningMediator()->unregisterSummonedMonster(this);}inline void MonsterSummoningMediator::distributeAttackCommand() {    for (SummonedMonster* x : summonedMonsters)        x->receiveAttackCommand();}inline void MonsterSummoningMediator::distributeShieldMeCommand() {    for (SummonedMonster* x : summonedMonsters)        x->receiveShieldMeCommand();}inline void MonsterSummoningMediator::destroySummonedMonsters() {    for (SummonedMonster* x : summonedMonsters)        delete x;    summonedMonsters.clear();}int main() {    Wizard wizard({Merlin, 25, 9});    Fighter fighter({Borg, 48, 18});    wizard.castsMonsterSummoning();    for (LivingBeing* x : allBeingsPresent)        std::cout << x->name <<  (hit points =  << x->hitPoints << , strength =  << x->strength << ) is present.\n;    wizard.orderSummonedMonstersToAttack();    wizard.orderSummonedMonstersToShieldMe();    fighter.attacks(allBeingsPresent.back());  // The summoned monster dies.    wizard.dies();}