I am learning a lot about design patterns when I am building my own system for my projects. And I want to ask you about a design question that I can't find an answer to.
Currently I am building a little Chat-server using sockets, with multiple Clients. Right now I have three classes:
- Person-class which holds information like nick, age and a Room-object.
- Room-class which holds information like room-name, topic and a list of Persons currently in that room.
- Hotel-class which have a list of Persons and a list of Rooms on the server.
I have made a diagram to illustrate it:
I have a list of persons on the server in the Hotel-class because it would be nice to keep track of how many there are online right now (Without having to iterate through all of the rooms).
The persons live in the Hotel-class because I would like to be able to search for a specific Person without searching the rooms.
Is this bad design? Is there another way of achieve it?
Thanks.
The mutual dependency problem among the classes, strictly speaking, can be solved by using interfaces (abstract classes, if your language is e.g. C++ or Python) IRoom
and IPerson
; in pseudocode
interface IPerson
IRoom getRoom()
// etc
interface IRoom
iter<IPerson> iterPerson()
// etc
this makes only the interfaces mutually dependent on each other -- the actual implementations of the interfaces need only depend on the interfaces.
This also gives you plenty of leeway in terms of implementation, if you want avoid circular reference loops (which can be a bother e.g. in CPython by slowing down garbage collections) -- you could use weak references, an underlying relational database with a typical "one to many relationship" table, etc, etc. And for the first simple prototype you can use what's simplest in your chosen language (probably simple, and alas necessarily circular, references [[pointers, in C++]] with a Person
referring to a Room
and a Room
to a list<Person>
).
I don't like it. A hotel contains rooms, and rooms contain people. People don't contain rooms, they belong to them.
You don't necessarily have to iterate to get your guest count. You could just keep a running count ($Hotel->total_guests) and modify it as it changes.
In a larger system, it would be bad, but since from what I understand of your applications, these three classes are only use together, it's not much of a problem. Just make sure to name the person's member variables in a way that indicates that it contains a reference to a room, rather than an instance.
Also, unless it's for performance reasons (e.g. you will have a huge number of rooms), it would probably be cleaner to make a property or getter that would iterate over the rooms and collect the persons, rather than caching them in the hotel.
Mutual dependency is not bad in its own right. Sometimes the data usage requires it.
I think about it in a different way. It'll be easier to maintain code that has fewer relationships in general-- mutual dependency or not. Just keep it as simple as possible. The only additionally trickiness with your situation is sometimes there's a check and egg problem, during create and delete sequences. You've got more links to bookkeep.
If you're asking about whether you need a list of persons on a hotel in this case, I think there are two answers. I'd start out by having your objects (in memory) supplying these relationships, but you do NOT need an additional join table between people and hotels in the database. If you are using Hibernate, it will automatically generate an efficient join for your if you ask it for the people in a hotel (it will join hotels on rooms.hotel_id for you).