So there are several places in my code where two objects reference each other (for the sake of argument, include 1:1 cardinality). So a Man object might have a m_husband reference to a Woman object which then has a m_wife reference back to him. The references should be mutually consistent, of course;
man->m_wife->m_husband == man
should always be true, for instance.
Now, the tricky part is where the invariant is temporarily violated in a SetHusband or SetWife method. Here's a few approaches I've used in the past, of varying wisdom.
The "shit, infinite loop" approach
void Man::SetWife(Woman* wife)
{
m_wife = wife;
m_wife->SetHusband(this);
}
void Woman::SetHusband(Man* husband)
{
m_husband = husband; m_husband->SetWife(this);
}
The "whatever you do, don't call THAT one" approach
void Man::SetWife(Woman* wife)
{
m_wife = wife;
m_wife->SetHusband(this);
}
void Woman::SetHusband(Man* husband) // DON'T CALL THIS METHOD EXCEPT FROM Man::SetWife!!!!!!
{
assert(husband->GetWife() == this);
m_husband = husband;
}
The "be nice to each other's internals" approach
// Man and Woman have each other as friend classes
void Man::SetWife(Woman* wife)
{
m_wife = wife;
m_wife->m_husband = this;
}
void Woman::SetHusband(Man* husband)
{
m_husband = husband;
m_husband->m_wife = this;
}
The "I now pronounce you man and wife" approach
void Marry(Man* husband, Woman* wife) // Friend function of Man and Woman
{
husband->m_wife = wife;
wife->m_husband = husband;
}
The "I heard you the first time" approach
void Man::SetWife(Woman* wife)
{
if(m_wife != wife)
{
m_wife = wife;
m_wife->SetHusband(this);
}
}
void Woman::SetHusband(Man* husband)
{
if(m_husband != husband)
{
m_husband = husband;
m_husband->SetWife(this);
}
}
The first approach obviously doesn't work. The second is what I have foolishly changed the first to, in times where I don't have the willpower to do anything less hackish. I don't like the third one because of the way it breaks encapsulation and makes coupling stronger. The fourth one is cute, but I dislike splitting out the functionality like that and increasing code repetition. So I've been doing the fifth one more and more. The big thing I don't like about the fifth method, though, is that it is transparently idempotent. Setting the wife to something it's already set to, in my opinion, should raise warning flags, and there is no way I can think of to do that.
I've expressed this all in terms of mutual references, BTW, but the general case I'm interested in is two classes which in any way have a mutual state dependence and where a change to part of the dependent state might be initiated from either side.
What do y'all think? What have you used in the past? Is there a Sixth Way I'm not considering?