【问题标题】:Managing multiple interdependent models管理多个相互依赖的模型
【发布时间】:2011-05-03 10:45:57
【问题描述】:

我正在尝试在基于消息传递的系统中管理多个模型。每个模型可能具有依赖于其他模型的值。例如:

   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);
      }
   }

我也想使用 MVC 模式,但不是传递模型实例,而是传递一个“存储库”实例。 “存储库”实例将充当处理所有模型实例的管理器。结果看起来像这样:

   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;
      }
   }

在这种情况下,如果 V1Model 的属性发生变化,在 V1ModelPropertyChanged 中,我会知道对 V2Model 对象的依赖关系,并使用适当的值对其进行更新。有没有更好的方法来处理这种相互依赖的模型方案,或者这是一个可以接受的解决方案?我并不是真的在寻找任何第 3 方。

【问题讨论】:

  • K.I.S.S. 发生了什么作为设计模式?你能抽象地解释你在没有代码的情况下想要实现的目标吗?也许有一个比您开始使用的解决方案更简单的解决方案。
  • @SyntaxC4 - 我不认为这个例子那么复杂。我的前两句话解释了我想要做什么......
  • @SyntaxC4 微软几年前就杀了它。

标签: c# winforms model-view-controller models


【解决方案1】:

如果你想优雅地处理这个问题,你需要让一些组件跟踪模型之间的依赖关系。当一个属性发生变化时,您将遍历该属性的所有依赖项,然后适当地更新它们。

也许您的BaseRepository 可能包含对DependencyManager 类的引用。该类必须有一个包含所有相互依赖的属性的列表。

一个简单的实现可能如下所示:

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;
            }
         }
     }
}

然后,当您检测到属性更改时,您可以查询 DependencyManager 以了解其他需要更改的内容。但是在级联时要小心检查循环依赖!

【讨论】:

  • 感谢您的建议,这绝对是一个可能的解决方案。
【解决方案2】:

也许我遗漏了一些东西,但这不是 observer pattern 的用途吗?如果您将模型设置为彼此的观察者(即,使用委托或事件),那么控制器应该能够保持对依赖关系的无知。

【讨论】:

  • +1 除非我也遗漏了什么……虽然我觉得在 .NET 中使用事件/委托会更优雅。
  • 这意味着每个模型都会收到有关每个 PropertyChanged 事件的通知,即使他们不关心它。想象一下模型 1 中的属性发生更改的场景,该更改通知所有模型有关更改,这会更改模型 2 中的值。然后,model2 中的更改会通知所有模型,并不断通知。这不是最直接的方式。我正在寻找一个解决方案,说,嘿,这个属性刚刚改变,这个其他模型有一个基于该值计算的值,去更新它。
  • 通常你想要这种行为,这样当你的模型随着时间的推移而增长时,他们可以决定他们关心什么信息,而无需改变其他模型或控制器。添加一个新的依赖字段/属性意味着您只更改一个模型/类而不是两个(您正在更新的模型加上它所依赖的模型)甚至三个(您正在更新的模型,它依赖的模型和控制器)。
  • 也意味着如果您使用事件和事件处理程序,模型实际上只会“通知”他们感兴趣的更改。对于给定的模型,您只需为事件创建和注册事件处理程序(属性更改)该模型关心的。
  • 有道理,但这里的通知只是问题的一半。另一个问题是能够访问其他模型信息。如果我只是通过 PropertyChanged 连接事件,我只有更改的属性名称,我没有每个模型的实例,除非我将存储库传递给每个模型,我真的不想这样做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-04
  • 2012-09-06
  • 2013-03-26
  • 2014-10-15
  • 2016-04-06
  • 1970-01-01
相关资源
最近更新 更多