Say we have 2 Classes: Account and Contact like this:
class Account {
string Id;
string Name;
}
class Contact {
string Id;
string FirstName;
string LastName;
}
An account can contain many contacts. This data is managed in a class "DataManager" which acts as the repository for the rest of the program. There are 2 main requirements:
- For an Account, I need to retrieve a list of its Contacts
For a given accountId or contactId I need to retrieve the respective Account/Contact. The retrievement of a contact should work, even if I don't know which Account the contact is assigned to. Like this
Contact c = dataManager.GetContact(contId);
I discussed with a colleague the following 2 options to implement the Account-Contact relation in C++:
Option 1: Store hierarchically ... the Account class would contain a map of contacts. Key of that map would be the ContactId. The DataManager would store a map of accounts:
class DataManager {
Account& GetAccount(string accountId);
Contact& GetContact(string contactId);
map<string, Account> accounts;
}
class Account {
map<string, Contact> contacts;
Contact& GetContact(string contactId);
list<reference_wrapper<Contact>> GetContacts();
}
Problem: The implementation of DataManager:: GetContact would need to iterate over all account's contacts. As an alternative, I could store a map of contactId -> accountId in the DataManager to quickly dereference the account that contains the required contact.
Option 2: "Flat" storage" In this solution, the objects are all stored in the DataManager. The account class only stores the Id's of its contacts.
class DataManager {
map<string, Account> accounts;
map<string, Contact> contacts;
Account& GetAccount(string accountId);
Contact& GetContact(string contactId);
}
class Account {
map<string, string> contactIds;
list<string> GetContactIds();
}
Problem: To get a list of all contacts of an account, the calling code (-> in real: some code in the DataManager) needs to iterate over the list of contactIds retrieved by the Account object and collect the respective contact objects from the DataManager.
Option 2.1 Reference wrapper What about containers using reference_wrapper instead of string contactId? (as suggested by @Caleth)
What to do? Which of these options seems more legit to you - or do you suggest a different solution?
reference_wrapper<Contact>
instead ofstring
contactId?