SwDevMan81
SwDevMan81

Reputation: 49978

Managing multiple interdependent models

I’m trying to manage multiple models in a messaging based system. Each model might have values that are dependent on other models. For example:

   public class V2Model : BaseModel
   {
      private int mSomeVal;
      private byte mSomeByte;

      // …

      // Update mSomeByte based on multiple models values
      public void SetMultipleDependecyValue(int someIntFromModel1, short someShawteeyFromModel3)
      {
         mSomeByte = Convert.ToByte((someShawteeyFromModel3 / someIntFromModel1) + mSomeVal);
      }
   }

I would also like to use the MVC pattern, but instead of passing a Model instance, I thought I would pass in a ‘Repository’ instance. The ‘Repository’ instance would act as a manager for handling all the Model instances. The result would look something like this:

   public class V1Controller<ViewType, ModelType>
      where ViewType : IV1View
      where ModelType : BaseModel
   {
      ViewType mView;
      BaseRepository mBaseRep;

      public V1Controller(ViewType view, BaseRepository rep)
      {
         mView = view;
         mBaseRep = rep;
         mBaseRep.GetModel<ModelType>().PropertyChanged += new PropertyChangedEventHandler(V1ModelPropertyChanged);
      }

      void V1ModelPropertyChanged(object sender, PropertyChangedEventArgs e)
      {
         switch (e.PropertyName)
         {
            case "SomeVal":
               // Update the view
               int some_val = mBaseRep.GetModel<ModelType>().SomeVal;
               mView.HexSomeValue = some_val;
               // Oh BTW, we know V2Model's value depends on this... update it with V1Model and V3Model's values
               short some_short = mBaseRep.GetModel<V3Model>().SomeShawteey;
               mBaseRep.GetModel<V2Model>().SetMultipleDependecyValue(some_val, some_short);
               break;
         }
      }

      public void UpdateVal(int someValue)
      {
         mBaseRep.GetModel<ModelType>().SomeVal = someValue;
      }
   }

In this situation, if V1Model’s property changed, in V1ModelPropertyChanged, I would know the dependency on V2Model’s object, and update it with the appropriate values. Is there a better way of handling this interdependent model scheme, or would this be an acceptable solution? I am not really looking for anything 3rd party.

Upvotes: 1

Views: 599

Answers (2)

super_seabass
super_seabass

Reputation: 1116

Maybe I'm missing something, but isn't this what the observer pattern is for? If you set up the models as observers of each other (i.e., with delegates or events), then the controller should be able to remain blissfully ignorant of the dependencies.

Upvotes: 1

Dan
Dan

Reputation: 921

If you want to handle this elegantly, you're going to need to have some component track the dependencies between the models. When a property changes, you would iterate over all of the dependencies for that property and then update them appropriately.

Perhaps your BaseRepository might hold a reference to a DependencyManager class. That class would have to have a list of all properties which depend on one another.

A simple implementation might look like this:

class PropertyDescriptor
{
    public Type ModelType { get; set; }
    public string Property { get; set; }
}

class DependencyManager
{
    private Dictionary<PropertyDescriptor, List<PropertyDescriptor>> _dependencies = new Dictionary<PropertyDescriptor, List<PropertyDescriptor>>();

    public void RegisterDependency(PropertyDescriptor property, PropertyDescriptor dependentProperty)
    {
        if (!_dependencies.ContainsKey(property))
        {
            _dependencies.Add(property, new List<PropertyDescriptor>());
        }
        _dependencies[property].Add(dependentProperty);
    }

    public IEnumerable<PropertyDescriptor> GetDependentProperties(PropertyDescriptor property)
    {
        if (!_dependencies.ContainsKey(property))
        {
            yield break;
        }
        else
        {
            foreach (PropertyDescriptor p in _dependencies[property])
            {
                yield return p;
            }
         }
     }
}

Then when you detect a property change, you can query the DependencyManager for what else needs to change. But be careful to check for circular dependencies when you cascade!

Upvotes: 1

Related Questions