Модель ответственности MVVM
Это основной вопрос MVVM.
Допустим, у меня есть окно редактора студента, которое позволяет пользователю установить метод оплаты студента (наличными или чеком). Для обеспечения гибкости возможные способы оплаты должны быть получены с сервера, а список зависит от возраста учащегося, который также может быть изменен.
Вопросы:
где следует хранить возможные способы оплаты? Модель или вид модели?
Если модель, когда пользователь меняет возраст, кто должен загрузить новый список способов оплаты?
что модель должна содержать и делать в MVVM?
2 ответа
Модель является логическим местом для размещения методов оплаты и бизнес-правил, связанных с каждым методом. Один из подходов состоит в том, чтобы использовать перечисление, описывающее каждый метод оплаты, и это запрашивается с помощью операторов "switch".
Альтернативный дизайн включает в себя сильные стороны полиморфизма и может выглядеть следующим образом...
public class Model
{
private readonly List<PaymentMethod> _allPaymentMethods;
public Model()
{
// get payment types from the db
// to populate master list
_allPaymentMethods = new List<PaymentMethod> {new Cash(), new CreditCard()};
}
public List<PaymentMethod> GetPaymentMethods(int age)
{
List<PaymentMethod> result =
_allPaymentMethods.Where(q => q.Age == age).ToList();
return result;
}
}
public abstract class PaymentMethod
{
public string Name { get; protected set; }
public int Age { get; protected set; }
public abstract void ProcessPayment();
public override string ToString()
{
return Name;
}
}
public class CreditCard:PaymentMethod
{
public CreditCard()
{
Name = "Credit Card";
Age = 25;
}
public override void ProcessPayment()
{
Console.WriteLine("Thanks for using your card");
}
}
public class Cash:PaymentMethod
{
public Cash()
{
Name = "Cash";
Age = 22;
}
public override void ProcessPayment()
{
Console.WriteLine("Thanks for paying cash");
}
}
Этот пример жестко кодирует два метода: Cash и Credit Card, и каждый класс знает, как выполнять свою работу, полагаясь на наследование для обработки общих атрибутов. Этот подход избегает "переключения" и включает в себя все бизнес-правила и методы в каждом классе. Таким образом, Модель предоставляет только то, что необходимо знать ViewModel, чтобы представить пользователю различные способы оплаты в элементе управления товарами.
Когда пользователь меняет свой возраст, ваша виртуальная машина может обновить список.
Фрагмент кода для виртуальной машины выглядит так...
public class ViewModel :INotifyPropertyChanged
{
public ObservableCollection<PaymentMethod> Methods { get; set; }
public ViewModel()
{
Model m = new Model();
Methods = new ObservableCollection<PaymentMethod>(m.GetPaymentMethods(22));
}
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
var handler = System.Threading.Interlocked.CompareExchange
(ref PropertyChanged, null, null);
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
Какой бы подход вы ни использовали (перечисление или полиморфизм), практическое правило гласит: "Нужно ли виртуальной машине знать об этом? Могу ли я использовать преимущества ОО наследования и полиморфизма в моей архитектуре?"
Ну, по моему мнению, модель должна содержать список способов оплаты, а виртуальная машина должна содержать список для привязки к представлению. Пример, что я хотел бы сделать, это иметь List<PaymentOptions>
на модели и BindingList<PaymentOptions>
или же ObservableCollection<PaymentOptions>
для ВМ.