tags:

views:

110

answers:

3

Hello, I've been pondering the best way to implement a certain kind of functionality... that being derived objects referencing other derived objects with the same base (including mutual referencing).

Below is the best (simple) example I could think of to illustrate the kind of problem: a house made up of 3 rooms (though in practice it could be hundreds) each represented by its own derived class. Of course it won't work as it stands, it would cause a stack overflow (appropriately!)

Assuming each room in the example is specific to a room in an imaginary house, there should be no more than one instance of any subclass. Constructing lots of instances, even without the recursion, would be messy. That would make me think singleton if that weren't such a taboo... can anyone suggest something more appropriate?

Thank you!

public abstract class Room
{
    abstract public void DoAction();
    public Room[] ConnectedRooms;
}

public class Kitchen : Room
{
    public Kitchen() { ConnectedRooms = new Room[] { new Hall() }; }
    public override void DoAction() { MakeTea(); }
}

public class Bedroom : Room
{
    public Bedroom() { ConnectedRooms = new Room[] { new Hall() }; }
    public override void DoAction() { Sleep(); }
}

public class Hall : Room
{
    public Hall() { ConnectedRooms = new Room[] { new Hall(), new Bedroom() }; }
    public override void DoAction() { LookOutWindow(); }
}
+4  A: 

Your rooms should contain references to an instance of each other rooms - not new instances.

e.g. create a new Kitchen, Hall, Bedroom. Then pass a reference of the Hall to the Bedroom, to the Kitchen etc. That way you have your three objects, and they have references to the neighbouring rooms.

Kitchen k = new Kitchen();
Bedroom b = new Bedroom();
k.addNeighbour(b);

etc.

(I'd normally construct a Kitchen with appropriate references, but you appear to have circular references, so that's not so easy)

If you really need only one instance of each, then check out the singleton pattern. However I wouldn't enforce that unless strictly necessary. After all, lots of houses have more than one bedroom!

Brian Agnew
My thoughts exactly. I don't think a singleton is at all appropriate here, either, since you probably will want multiple instances of certain types of rooms... Even if you didn't, it just adds complexity that's unneeded.
Reed Copsey
The idea is right, create all the rooms once and hold reference for the connections instead of creating every room multiple times.
Peter Schuetze
Thank you that's interesting, although it would require moving the connection definition away from the class definition... which I suppose has pros and cons. In the class definition it would be easy to find where the class' connections were defined. However having all the connections defined in one place has merits too.
Bobbins
Each class could derive from the same abstract base class that records the connections in one instance of a "master" class. It sounds like you need a "Building" class that has the canonical view of what's going on.
Brian Agnew
Downvoted why? Can you give a reason why the above is wrong or unhelpful?
Brian Agnew
A: 

All you need to do is avoid instantiating one room within the constructor of another. You'll need to instantiate all of your rooms (Kitchen k = new Kitchen(); Hall h = new Hall();), and then add the connections (k.ConnectedRooms[0] = h; h.ConnectedRooms[0] = k;). Or, to be clever, create a method that mutually connects them:

public abstract class Room
{
public void Connect(Room r)
{
this.ConnectedRooms.Add(r);
r.ConnectedRooms.Add(this);
}
}

Assuming you change your connection arrays to lists, which is probably a good idea.

Eric Mickelsen
+2  A: 

You really need to encapsulate (Is this the right word?) your model further.

public class House
{  
    private readonly Hall hall = new Hall();
    private readonly Kitchen kitchen = new Kitchen();

    // etc

    public House()
    {
        hall.AddAdjacentRoom(kitchen);
        // etc
    }

}
ChaosPandion
Nicely put, a House class would really tie the rooms together.
Bobbins