Safety between friends

In this exercise, World needs access to the Vitals of the Creature. Only World should be allowed to have access to the Vitals of Creature, and no other class should be allowed to access them.

In C++, you could make World a friend of Creature. Friend however is evil. First, it allows World to access everything in Creature. Secondly, it can easily be gotten around by the evil third party that wants to access Vitals by just changing the header file for its own compilation to include itself as a friend. The protection is only applied at compile time of the class doing the access. This sucks.

The technique demonstrated below allows access to Vitals only to World, without giving World any access to any other internals. It pulls this off by having a method called give_vitals_to_world() which takes a World argument.

So when World wants access to Vitals, it calls give_vitals_to_world(this) on the Creature, which in turn calls accept_vitals_from_creature(internal_vitals) on the World which was passed to it.

In the demonstration below, World has a method called increase_life() which is allowed to increase the energy of the Creature. If you follow the code from that point, the technique should be made clear.

Note that altho I implemented my demonstration of the technique in C#, it could be written in C++ or Java or ObjC, etc..

public class Creature {
    public class Vitals {
        public int energy;
    };

    private Vitals _vitals;

    public Creature() {
        _vitals = new Vitals();
    }

    public int Energy { get { return _vitals.energy; } }

    public void give_vitals_to_world(World w) {
        w.accept_vitals_from_creature(_vitals);
    }
};

public class World {
    private Creature.Vitals _tmpstats;

    public void accept_vitals_from_creature(Creature.Vitals stats) {
        _tmpstats = stats;
    }

    private Creature.Vitals GetStats(Creature c) {
        c.give_vitals_to_world(this);
        return _tmpstats;
    }

    public void increase_life(Creature c) {
        if (some condition is met)
            GetStats(c).energy++;
    }
};