2012-01-29 66 views
1

我有一個對象層次結構,它是使用MVVM模式的WPF應用程序的模型。後代對象需要知道在層次結構的根對象上設置的屬性。該屬性可以隨時更改(不僅在創建層次結構時進行設置)。在這個要求出現之前,孩子沒有理由引用它的父代或根對象。MVVM模型層次結構中的共享值

簡化,簡寫例如:

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屬性添加到需要它的後代對象。當根狀態改變時更新後代的狀態。

PRO's:對象層次仍然不需要孩子知道父母/根。

CON's:隨着模型演變,很容易錯過所需的更新。兒童的IsFlying狀態可以被根對象以外的人改變。更復雜。

我傾向於在每個後代中引用對根的引用,但希望看看我是否缺少更優雅的解決方案,或者如果我錯過/低估了該路徑的重要結果。

回答

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

訣竅是創建基類和懶洋洋地設置parent屬性爲您集合或枚舉子對象。這是一個相當靈活的模式。

+0

這對優雅的實施方案A的可能機制父,但並不能幫助我可用的選項之間進行選擇。感謝您的輸入。 – 2012-01-30 02:26:16

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