Использование неанемичной доменной модели с Wpf MVVM - PullRequest
6 голосов
/ 29 марта 2011

Я реализую приложение на основе WPF с использованием MVVM для пользовательского интерфейса.

У меня есть ViewModel, который оборачивает каждую редактируемую модель, которую можно редактировать.Виртуальная машина содержит всю логику для обработки уведомлений об ошибках, «грязного» управления и т. Д., не содержат никакой логики.

Теперь я столкнулся с более сложной проблемой, потому что у меня есть модель предметной области, которая содержит логику, и эта логика может изменить внутреннее состояние модели предметной области.

Кто-то уже сталкивался с таким сценарием?Если да, то есть ли у вас какие-либо советы, чтобы справиться с этим правильно?

Riana

Ответы [ 3 ]

9 голосов
/ 29 марта 2011

Вот как я обычно с этим справляюсь:

  1. Слой ViewModel состоит из типов, принадлежащих этому слою, то есть я никогда не использую свои бизнес-объекты напрямую внутриViewModel.Я сопоставляю свои бизнес-объекты с объектами ViewModel, которые могут иметь или не иметь одинаковую форму за вычетом поведения.Можно утверждать, что это нарушает принцип «Не повторяйся сам», но это позволяет вам придерживаться принципа единой ответственности.На мой взгляд, SRP обычно должен превзойти DRY.ViewModel существует для обслуживания представления, а модель существует для обслуживания бизнес-правил / поведения.

  2. Я создаю фасадный / сервисный слой, который принимает и возвращает ViewModels в качестве аргументов, но отображает ViewModelsк-и-от их соответствующих версий бизнес-объекта.Таким образом, неанемичные объекты не будут навязывать логику без представления для ViewModel

Зависимости будут выглядеть следующим образом:
ViewModel <-> Facade / ServiceLayer -> Бизнес-объекты

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

2 голосов
/ 29 марта 2011

Попробуйте использовать шаблон команды. Ваш экран должен быть предназначен не для редактирования объекта, а для выполнения действия (команды) над объектом. Если вы будете следовать этому принципу при разработке своих экранов, ваша ViewModel будет иметь свойства, которые должны быть сопоставлены с командным объектом. Затем команда будет отправлена ​​на (удаленный) фасад модели домена.

ViewModels для отображения данных может быть отображен непосредственно в базу данных (полностью обходя модель домена), так что вам не нужно помещать неприятные методы получения в классы модели домена.

1 голос
/ 23 апреля 2012

Если модель домена не является анемичной, вам нужно будет использовать события , чтобы сообщить о внутренних изменениях в модели обратно в ViewModel. Таким образом, вам не нужно беспокоиться о том, чтобы отслеживать, какие операции могут привести к несинхронизации виртуальной машины с моделью.

Вот простой пример:

Сначала образец модели:

public class NonAnemicModel
{
    private string _name;

    public string Name
    {
        get { return _name; }
        set
        {
            if (_name == value)
                return;

            _name = value;
            OnNameChanged(EventArgs.Empty);
        }
    }

    public event EventHandler NameChanged;
    protected virtual void OnNameChanged(EventArgs e)
    {
        if (NameChanged != null)
            NameChanged(this, e);
    }

    public void PerformNameCalculation(int chars)
    {
        //example of a complex logic that inadvertently changes the name
        this.Name = new String('Z', chars); //makes a name of Z's
    }
}

А вот пример ViewModel:

public class MyViewModel : INotifyPropertyChanged
{
    private NonAnemicModel _model;

    public NonAnemicModel Model 
    {
        get { return _model; }
        set
        {
            _model = value;
            _model.NameChanged += (sender, args) => NotifyPropertyChanged("UserName");
        }
    }

    public string UserName 
    {
        get { return this.Model.Name; }
        set { this.Model.Name = value; }
    }

    //this command would call out to the PerformNameCalculation method on the Model.
    public ICommand PerformNameCalculation { get; private set; }
}

Обратите внимание, что событие PropertyChanged возникает при изменении имени в модели. Таким образом, независимо от того, использовался ли установщик UserName или команда PerformNameCalculation, ViewModel остается синхронизированным. Большим недостатком этого является то, что вам нужно добавить намного больше событий в вашу модель, но я обнаружил, что наличие этих событий обычно очень полезно в долгосрочной перспективе. Только будьте осторожны с утечками памяти при событиях!

...