Here's a common scenario that's always frustrating for me to deal with.
I have an object model with a parent object. The parent contains some child objects. Something like this.
public class Zoo
{
public List<Animal> Animals { get; set; }
public bool IsDirty { get; set; }
}
Each child object has various data and methods
public class Animal
{
public string Name { get; set; }
public int Age { get; set; }
public void MakeMess()
{
...
}
}
When the child changes, in this case when the MakeMess method is called, some value in the parent needs to be updated. Let's say when a certain threshold of Animal's have made a mess, then the Zoo's IsDirty flag needs to be set.
There are a few ways to handle this scenario (that I know of).
1) Each Animal can have a parent Zoo reference in order to communicate changes.
public class Animal
{
public Zoo Parent { get; set; }
...
public void MakeMess()
{
Parent.OnAnimalMadeMess();
}
}
This feels like the worst option since it couples Animal to its parent object. What if I want an animal who lives in a house?
2) Another option, if you're using a language that supports events (like C#) is to have the parent subscribe to change events.
public class Animal
{
public event OnMakeMessDelegate OnMakeMess;
public void MakeMess()
{
OnMakeMess();
}
}
public class Zoo
{
...
public void SubscribeToChanges()
{
foreach (var animal in Animals)
{
animal.OnMakeMess += new OnMakeMessDelegate(OnMakeMessHandler);
}
}
public void OnMakeMessHandler(object sender, EventArgs e)
{
...
}
}
This seems to work but from experience gets hard to maintain. If Animals ever change Zoo's you have to unsubscribe events at the old Zoo and resubscribe at the new Zoo. This only gets worse as the composition tree gets deeper.
3) The other option is to move the logic up to the parent.
public class Zoo
{
public void AnimalMakesMess(Animal animal)
{
...
}
}
This seems very unnatural and causes duplication of logic. For example, if I had a House object that doesn't share any common inheritance parent with Zoo..
public class House
{
// Now I have to duplicate this logic
public void AnimalMakesMess(Animal animal)
{
...
}
}
I have not yet found a good strategy for dealing with these situations. What else is available? How can this be made simpler?