Стоимость акций в иерархии моделей MVVM - PullRequest
1 голос
/ 30 января 2012

У меня есть иерархия объектов, которая является моделью для приложения 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 к объектам-потомкам, которыетребовать этого.Обновлять состояние потомка при изменении состояния root.

PRO: объектная иерархия по-прежнему не требует, чтобы дети знали родителей / root.

CON: легко пропустить необходимое обновление по мере развития модели.Детское состояние IsFlying может быть изменено кем-либо, кроме корневого объекта.Более сложный.

Я склонен вводить ссылку на корень в каждом потомке, но хочу посмотреть, не хватает ли мне более элегантного решения, или я упускаю / недооцениваю важное последствие этогопуть.

Ответы [ 3 ]

1 голос
/ 30 января 2012

Не думаю, что есть что-то более простое, чем ваше первое предложение.

Второе - это открытие для потенциальных ошибок, и любое другое решение потребовало бы дополнительных классов, которые соединяют крылья с плоскостями.* Идите первым, и если в будущем ваши модели станут слишком сложными, разбейте их на дополнительные объекты.Не нужно беспокоиться об этом сейчас.

0 голосов
/ 30 января 2012

опция «A» идет вразрез с « слабой связью », что действительно ИМХО является наиболее важным принципом в архитектуре программного обеспечения.

Как минимум, ваши дети должны знать интерфейсили хуже самого родителя, чтобы реализовать это.Это означает, что ваш дочерний код будет привязан к родительскому коду.

Кроме того, если MVVM знает, что родительский объект не означает, что событие INotifyPropertyChanged произойдет автоматически у ваших детей.Что, если это требование, означает, что вы должны иметь свойство IsFlying для ребенка, независимо от того.Если это не является обязательным требованием, станет ли оно в будущем?

Возможны и другие варианты, которые остаются на свободном соединительном пути.наличие автономного делегата или функции на дочернем объекте, которое устанавливается родителем и возвращает родительское свойство IsFlying.

или при создании экземпляра дочерних элементов добавьте событие PropertyChanged на родительском объекте, которое обновляет дочерний пример

public class Airplane
{
    WingAssembly _wing;

    protected void CreateWing()
    {
        wing = new WingAssembly();
        PropertyChanged += (s,e) => wing.IsFlying = IsFlying; 
    }
}
0 голосов
/ 30 января 2012

Один шаблон, который мне очень помог, - это упрощенная модель контейнера. Проще говоря, определяя простой гомоморфный интерфейс для компонентов:

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

Хитрость заключается в создании базовых классов и коллекций, которые лениво устанавливают для вас родительское свойство или перечисляют дочерние объекты. Это довольно гибкий шаблон.

...