Object-Oriented Modeling – Patterns for Propagating Changes

modelingobject-oriented

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?

Best Answer

I had to deal with this a couple times. The first time I used option 2 (events) and as you said it became really complicated. If you go that route, I highly suggest you need very thorough unit tests to make sure the events are done correctly and you're not leaving dangling references, otherwise it's a really big pain to debug.

The second time, I just implemented the parent property as a function of the children, so keep a Dirty property on each animal, and let Animal.IsDirty return this.Animals.Any(x => x.IsDirty). That was in the model. Above the model there was a Controller, and the controller's job was to know that after I changed the model (all actions on the model were passed through the controller so it knew that something had changed), then it knew it had to call certain re-evaluation functions, like triggering the ZooMaintenance department to check if the Zoo was dirty again. Alternatively I could just push the ZooMaintenance checks off until some scheduled later time (every 100 ms, 1 second, 2 minutes, 24 hours, whatever was necessary).

I found the latter has been much simpler to maintain, and my fears of performance problems never materialized.

Edit

Another way of dealing with this is a Message Bus pattern. Rather than using a Controller like in my example, you inject every object with an IMessageBus service. The Animal class can then publish a message, like "Mess Made" and your Zoo class can subscribe to the "Mess Made" message. The message bus service will take care of notifying the Zoo when any animal publishes one of those messages, and it can re-evaluate its IsDirty property.

This has the advantage that Animals no longer need a Zoo reference, and the Zoo doesn't need to worry about subscribing and unsubscribing from events from every single Animal. The penalty is that all Zoo classes subscribing to that message will have to re-evaluate their properties, even if it wasn't one of its animals. That may or may not be a big deal. If there's only one or two Zoo instances, it's probably fine.

Edit 2

Don't discount the simplicity of option 1. Anyone revisiting the code won't have much problem understanding it. It'll be obvious to someone looking at the Animal class that when MakeMess is called that it propagates the message up to the Zoo and it'll be obvious to the Zoo class where it gets its messages from. Remember that in object-oriented programming, a method call used to be called a "message". In fact, the only time it makes much sense to break from option 1 is if more than just the Zoo has to be notified if the Animal makes a mess. If there were more objects that needed to be notified, then I would probably move to a message bus or a controller.

Related Topic