2

我发现很难理解如何最好地实现不是简单类型的“IView”接口属性,并且想知道其他人如何在 Model View Presenter 应用程序中处理这个问题。

我读过的文章非常好,但它们似乎都没有接近更复杂的视图,其中您具有 List<> 属性,这些属性是表示域模型中的类的接口类型,即 IPerson 或 IName 等。

我将尽可能简要地概述一个场景。

假设我需要 View 最终保留一个名称列表,每个名称由 3 个属性“Forename”、“Surname”和“Title”组成。

通常,我将有一个域模型,其中包含一个名为“Name”的类,具有 3 个属性。此域模型将实现一个名为“IName”的接口(在单独的“接口”类库中)。

现在在我的“Interaces”库中的“Views”命名空间中,我有一个名为“IViewNames”的接口。这是任何想要最终保留名称列表的视图都将实现的视图接口。

如何定义这个“IViewNames”界面让我很困惑。如果我给它一个这样的属性:

public List<IName> Names {get;set;}

那么我实现的具体视图最终将有一个复杂的属性'Names',它将需要一个'getter',它遍历视图上的字段,以某种方式实例化'IName'的一个实例,设置它的属性,添加到一个列表中,然后返回名单。'setter' 将同样复杂,接收 'INames' 列表并在视图中设置字段并遍历它们。

我觉得这打破了 MVP 方法的主要目标之一,即无需任何具体的视图实现就能够彻底测试应用程序代码。毕竟,我可以很容易地编写一个演示者来查看“View.Names”属性并将其发送到服务层,或者在从服务接收到“名称”对象列表时设置“View.Names”属性层。我可以轻松编写很多测试来确保一切正常,除了视图中的 COMPLEX 属性之外的所有内容。

所以我的问题是,其他人如何处理不是简单类型但实际上是您的域模型类型的 IView 属性?(代表您的域模型的接口类型很好,因为我显然不希望从我的表示层引用到我的域模型层)。

我非常确定有一种已知的技术可以以一种优雅的方式实现这一点,它比我的示例方法更符合模型视图演示器的目标。

提前感谢任何帮助的人。

4

2 回答 2

1

我在 MVP 设计模式上工作不多,但肯定会尝试一下。

方法1:数据绑定

在这种情况下,您还可以在 IView 中创建单独的属性,并将 Presenter 中的这些属性绑定到模型属性。这样,您的视图就不会变得复杂。由于 UI 中的值可以直接在模型中使用,因此体验快速且无缝。更改模型中的属性值将立即反映在 UI 中。您可能必须为此使用 NotifyPropertyChange 事件。

方法 2:复杂类型

您可以尝试创建列表或元组来存储这些值并在演示者中使用这些值。您可能必须使用事件或操作来反映模型到视图的价值,反之亦然。

请让我知道它是否对您有帮助。谢谢。

于 2012-12-11T07:29:33.260 回答
0

我已经从我在我的网站上写的一篇文章中取消了这个解释

演示者查看通信

有两种样式用于使用我使用过的 Presenter 和 Model 的数据填充视图。它们之间的唯一区别是您认为您的视图与模型的耦合程度如何。例如,我们将以下内容作为我们的模型:

public class Person
{
    public int ID { get; private set; }
    public int Age { get; set; }
    public String FirstName { get; set; }
    public String LastName { get; set; }
    Public Genders Gender { get; set; }
}

方法一:使用模型

现在我们的查看代码:

public interface IEmployeesView
{
    void ClearList();
    void PopulateList(IEnumerable<Person> people);
}

最后是演示者:

public class IEmployeesPresenter
{
    public void Display()
    {
        _view.ClearList();
        _view.PopulateList(_model.AllEmployees);
    }
}

这种填充方法在模型和视图之间产生了联系;用作参数的 Person 对象PopulateList

这样做的好处是 IEmployeesView 的具体实现可以决定在其人员列表中显示什么,从Person.

它们是这种方法的两个缺点。第一个是没有什么可以阻止 View 调用 上的方法Person,这使得惰性代码很容易溜进来。第二个是如果模型要从 a 更改为List<Person>aList<Dog>实例,不仅 Model 和Presenter 需要改变,但 View 也需要改变。

方法 2:使用泛型类型

另一个方法填充依赖于 usingTuple<...>KeyValuePair<,>自定义类和结构:

现在我们的查看代码:

public interface IEmployeesView
{
    void ClearList();
    void PopulateList(IEnumerable<Tuple<int, String> names);
}

最后是演示者:

public class IEmployeesPresenter
{
    public void Display()
    {
        var names = _model.AllEmployees.Select(x => new Tuple<int, String>(x.ID, x.FirstName + " " + x.LastName));

        _view.ClearList();
        _view.PopulateList(names);
    }
}

这种填充方法的优点是 Model 可以自由更改而无需更新 View,并且 View 没有决定要显示什么。它还阻止 View 调用 上的任何额外方法Person,因为它没有对它的引用。

这种方法的缺点是你失去了强类型和可发现性 - aPerson是什么很明显,但 aTuple<int, String>不太明显。

于 2012-01-25T16:39:00.253 回答