【问题标题】:MVVM model responsibilityMVVM 模型责任
【发布时间】:2013-08-04 02:11:53
【问题描述】:

这是一个基本的 MVVM 问题。

假设我有一个学生编辑器窗口,允许用户设置学生的付款方式(现金或支票)。为灵活起见,必须从服务器检索可能的付款方式,并且列表因学生的年龄而异,也可以更改。

问题是:

  1. 应该将可能的付款方式存储在哪里?模型还是视图模型?

  2. 如果是model,当用户改变年龄时,谁应该下载新的支付方式列表?

模型在 MVVM 中应该包含什么内容和做什么?

【问题讨论】:

  • 那么谁来决定为特定学生选择的付款方式是否有效,是服务器还是学生本身?

标签: wpf mvvm mvvm-light mvvm-foundation


【解决方案1】:

模型是存放支付方式和与每种方式相关的业务规则的逻辑位置。一种方法是使用描述每种付款方式的枚举,并使用“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 需要知道的内容,以便在项目控件中向用户展示各种支付方式。

当用户改变年龄时,你的虚拟机可以刷新列表。

VM 的代码 sn-p 看起来像...

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
}

无论您使用哪种方法(枚举或多态),经验法则是“VM 是否绝对需要知道这一点?我可以在我的架构中利用继承和多态的 OO 优势吗?”

【讨论】:

  • 此模型是否还包含学生属性,或者学生是否在其自己的模型中,也由 VM 管理?
  • @LostInComputer,我尝试在我的设计中实现高度隔离,因为它简化了测试和模拟。所以我会为学生使用相同的方法,即将业务规则放在模型中,并尽可能少地暴露给 VM。对模型进行单元测试,然后模拟出来以测试 VM。
【解决方案2】:

嗯,在我看来,模型应该包含支付方式列表,而 VM 应该包含一个绑定到视图的列表。例如,我要做的是在模型上使用List&lt;PaymentOptions&gt;,在虚拟机上使用BindingList&lt;PaymentOptions&gt;ObservableCollection&lt;PaymentOptions&gt;

【讨论】:

  • 嗨,我更新了问题以使付款方式动态
  • 您仍然可以有一个付款方式列表,并且这些付款方式具有适合年龄的属性,对吗?然后在 VM 中从列表中选择项目。示例:List _paymentMethods; BindingList _possiblemethods = _paymentMethods.Where(x=>x.Age>minimum_age)
猜你喜欢
  • 2013-04-03
  • 2013-12-09
  • 1970-01-01
  • 1970-01-01
  • 2020-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多