我有一个对象层次结构,它是使用MVVM模式的WPF应用程序的模型。后代对象需要知道在层次结构的根对象上设置的属性。该属性可以不时更改(它不仅仅是在创建层次结构时设置)。在此要求浮出水面之前,没有理由让孩子对其父级或根对象进行引用。
简化,缩写示例:
public class Airplane
public bool IsFlying { get; set}
public ObservableCollection<WingAssembly> WingAssemblies { get; set; }
public class WingAssembly
public void MethodNeedsIsFlyingState() { }
public Flaps Flaps { get; set; }
public class Flaps
public void MethodAlsoNeedsIsFlyingState() { }
我有两种模式来解决这个问题:
A)向子项添加父(或根)对象引用。
PRO:简单的改变,直接引用根对象的状态
CON:创建一个之前不需要的双向对象层次结构......我不确定我可能遇到的下游后果(更复杂的数据模型?)
B)将IsFlying属性添加到需要它的后代对象。当root的状态发生变化时,更新后代的状态。
PRO:对象层次结构仍然不需要孩子知道父/ root。
CON:随着模型的发展,很容易错过所需的更新。儿童的IsFlying状态可以由除根对象之外的其他人更改。更复杂。
我倾向于在每个后代中引入对根的引用,但是想知道我是否缺少更优雅的解决方案,或者我是否遗漏/低估了该路径的重要后果。
答案 0 :(得分:1)
我认为没有什么比你的第一个建议简单。
第二个是对潜在错误的开放,任何其他解决方案都需要额外的类将机翼连接到飞机。
使用第一个,如果将来您的模型变得太复杂,请将它们分解为其他对象。现在无需担心。
答案 1 :(得分:0)
对我来说效果很好的一种模式是简化的容器模型。简而言之,在组件上定义一个简单的同态接口:
public interface IContained
{
IContained Parent { get; set; }
}
您可以编写类似这些的扩展方法,以达到特定父级的层次结构中的任何级别:
public IContained GetContainer(this IContained ChildObject)
{
if (ChildObject == null) {
return null;
}
return ChildObject.Parent;
}
public T GetContainer<T>(this IContained ChildObject)
{
if (ChildObject == null)
return null;
ChildObject = ChildObject.Parent;
while (ChildObject != null && !ChildObject is T) {
ChildObject = ChildObject.Parent;
}
return (T)ChildObject;
}
要向下导航,您可以定义另一个简单的界面:
public interface IContainedComponent
{
IEnumerable<IContainedComponent> GetComponents();
}
诀窍在于创建基类和集合,它们可以懒惰地为您设置父属性,或者枚举子对象。这是一种相当灵活的模式。
答案 2 :(得分:0)
选项“A”与“Loose coupling”相反,其中恕我直言是软件架构中最重要的原则。
您的孩子至少需要知道一个界面,或者更糟糕的是父母本身才能实现它。这意味着您的子代码将与父代码绑定。
此外,MVVM知道父级并不意味着您的孩子会自动发生INotifyPropertyChanged事件。如果这是一个要求意味着你需要在孩子身上拥有一个IsFlying属性。如果不是要求,它将来会成为一个吗?
保持松散耦合路径的其他选项可能是。 在父母设定的孩子身上拥有一个自治的委托或功能,并返回父母的IsFlying财产。
或在实例化子项时,在更新子项的父项上添加PropertyChanged事件 示例
public class Airplane
{
WingAssembly _wing;
protected void CreateWing()
{
wing = new WingAssembly();
PropertyChanged += (s,e) => wing.IsFlying = IsFlying;
}
}