Model View Presenter - 如何在 IView 界面中实现复杂的属性

发布于 2024-11-29 11:10:21 字数 1044 浏览 1 评论 0原文

我发现很难理解如何最好地实现不是简单类型的“IView”接口属性,并且想知道其他人如何在模型视图演示器应用程序中处理此问题。

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

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

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

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

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

如何定义这个“IViewNames”接口让我困惑。如果我给它一个像这样的属性:

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

那么我实现的具体视图最终将有一个复杂的属性“Names”,它将需要一个“getter”,它循环遍历视图上的字段,以某种方式实例化“IName”的实例,设置其属性,在返回列表之前添加到列表中。 “setter”将同样复杂,接收“IName”列表并迭代它们以在视图上设置字段。

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

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

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

预先感谢任何帮助的人。

I am finding it difficult understanding how best to implement 'IView' interface properties which are not simple types, and was wondering how others approach this in a Model View Presenter application.

The articles i've read are really good but none of them seem to approach more complex Views where you have List<> properties which are of an interface type which represent a class in your domain model, i.e. IPerson, or IName etc.

I will try to outline a scenario as briefly as i possibly can.

Presume i have a requirement for a View to ultimately persist a list of names, each consisting of 3 properties 'Forename', 'Surname', and 'Title'.

Typically i will have a domain model with a class called 'Name' with the 3 properties. This domain model will implement an Interface (in a separate 'Interfaces' class Library) called 'IName'.

Now in the 'Views' namespace in my 'Interaces' library i have an interface called 'IViewNames'. This is the view interface which any view which wants to ultimately persist the list of names will implement.

How to define this 'IViewNames' interface puzzles me. If i give it a property like so:

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

then my implementing concrete view will ultimately have a complex property 'Names' which will need a 'getter' which loops through the fields on the View, somehow instantiate an instance of 'IName', set its properties, add to a List, before returning the List. The 'setter' will be just as complex, receiving a list of 'INames' and iterating through them setting fields on the View.

I feel like this is breaking one of the major goals of the MVP approach, which is being able to thoroughly test the application code without any concrete View implemntations. After all, i could easily write a presenter which looks at the 'View.Names' property and sends it on to a Service Layer, or set the 'View.Names' property when receiving a list of 'Name' objects back from the Service Layer. I could easily write a lot of tests which ensure everything works, everything except from that COMPLEX property in the View.

So my question is, how do others approach IView properties which are not simple types, but are in fact types of your domain model? (well types of interfaces which represent your domain model, as i clearly dont want a reference from my Presentation Layer to my Domain Model layer).

I'm more than certain there is a known technique to achieving this in an elegant way, which adheres to the Model View Presenter goals, more than my example approach does.

Thanks in advance for any help people.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

韬韬不绝 2024-12-06 11:10:21

我对 MVP 设计模式没有做过太多研究,但肯定会尝试一下。

方法1:数据绑定

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

方法 2:复杂类型

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

如果对您有帮助,请告诉我。谢谢。

I have not worked much on the MVP design pattern but will surely try my hands on it.

Approach1 : DataBinding

In this case you can also create individual properties in IView and bind these properties in presenter to the model properties. This way, your view will not get complicated. The experience is fast and seamless as the values from UI can be directly used in model. Changing the property value in model will reflect in UI immedietly. You may have to use NotifyPropertyChange events for this.

Approach 2 : Complex Types

You can try creating List or Tuples to store these values and use the values in the presenter. You may have to use events or actions to reflect the value from model to view and vice versa.

Please let me know if it helped you. Thanks.

柒七 2024-12-06 11:10:21

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

Presenter to View Communication

有两种样式用于使用我使用的 Presenter 和模型中的数据填充视图。它们之间的唯一区别在于您介意视图与模型的耦合程度。对于这个例子,我们将使用以下作为我们的模型:

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

方法 1:使用模型

现在我们的视图代码:

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

最后是 Presenter:

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

这种填充方法在模型和视图之间产生链接;用作 PopulateList 中参数的 Person 对象。

这样做的优点是 IEmployeesView 的具体实现可以决定在其人员列表中显示什么内容,从 Person 的任何或所有属性中进行选择。

这是该方法的两个缺点。第一个是没有什么可以阻止 View 调用 Person 上的方法,这使得惰性代码很容易溜进去。第二个是如果模型从 更改为例如,将 List 更改为 List,不仅模型和演示者需要更改,视图也需要更改。

方法 2:使用泛型类型

另一种方法依赖于使用 Tuple<...>KeyValuePair<,> 以及自定义类和结构:

现在是我们的视图代码:

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

最后是Presenter:

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无需决定显示什么。它还可以防止视图调用 Person 上的任何额外方法,因为它没有对其的引用。

这种方法的缺点是,您失去了强类型和可发现性 - Person 是什么非常明显,但 Tuple 则不太明显明显的。

I have lifted this explanation from one of the articles I am writing on my website

Presenter to View Communication

There are two styles utilised for populating the View with data from the Presenter and Model that I have used. The only difference between them is how tightly coupled you mind your View being to the Model. For the example of this, we will have the following as our 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; }
}

Method 1: Using the Model

Now our View code:

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

And finally the Presenter:

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

This method of population produces a link between the Model and the View; the Person object used as a parameter in PopulateList.

The advantage of this is that the concrete implementation of the IEmployeesView can decide on what to display in its list of people, picking from any or all of the properties on the Person.

Their are two disadvantages of this method. The first is that there is nothing stopping the View from calling methods on the Person, which makes it easy for lazy code to slip in. The second is that if the model were to change from a List<Person> to a List<Dog> for instance, not only would the Model and the Presenter need to change, but so the View would too.

Method 2: Using Generic Types

The other method population relies on using Tuple<...>, KeyValuePair<,> and custom classes and structs:

Now our View code:

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

And finally the Presenter:

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

The advantages of this method of population is that the Model is free to change without needing to update the View, and the View has no decisions to make on what to display. It also prevents the View from calling any extra methods on the Person, as it does not have a reference to it.

The down sides to this method, are that you loose strong typing, and discoverability - It is quite obvious what a Person is but what a Tuple<int, String> is less obvious.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文