我发现很难理解如何最好地实现非IV类型的'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'循环遍历View上的字段,以某种方式实例化一个'IName'实例,设置它的属性,添加到List ,在返回List之前。 'setter'将同样复杂,接收一个'INames'列表并在View中迭代它们设置字段。
我觉得这打破了MVP方法的主要目标之一,即能够在没有任何具体View实现的情况下彻底测试应用程序代码。毕竟,我可以轻松地编写一个查看“View.Names”属性并将其发送到服务层的演示者,或者在从服务接收到“名称”对象列表时设置“View.Names”属性层。我可以很容易地编写很多测试来确保一切正常,除了View中的那个COMPLEX属性之外的所有东西。
所以我的问题是,其他人如何处理不是简单类型的IView属性,但实际上是你的域模型的类型? (以及代表您的域模型的接口类型,因为我显然不希望从我的表示层到我的域模型层的引用)。
我不仅仅确定有一种已知的技术可以以优雅的方式实现这一目标,这符合模型视图演示者目标,而不仅仅是我的示例方法。
提前感谢任何人的帮助。
答案 0 :(得分:1)
我在MVP设计模式上没有多少工作,但肯定会尝试一下。
Approach1:DataBinding
在这种情况下,您还可以在IView中创建单个属性,并将演示者中的这些属性绑定到模型属性。这样,您的视图就不会变得复杂。由于UI中的值可以直接用于模型,因此体验快速且无缝。更改模型中的属性值将立即反映在UI中。您可能必须使用NotifyPropertyChange事件。
方法2:复杂类型
您可以尝试创建List或Tuples来存储这些值并使用演示者中的值。您可能必须使用事件或操作来反映模型到视图的值,反之亦然。
如果有帮助,请告诉我。感谢。
答案 1 :(得分:0)
我从我在网站上写的articles之一解除了这个解释
有两种样式用于使用我使用的Presenter和Model中的数据填充View。它们之间的唯一区别在于您将View视为模型的紧密耦合。举个例子,我们将以下列模型:
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
上的方法,这使得懒惰代码很容易滑入。第二个是如果模型要从List<Person>
更改为例如,List<Dog>
,不仅模型和演示者需要更改,而且视图也是如此。
其他方法的人口依赖于使用Tuple<...>
,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);
}
}
这种人口方法的优点是模型可以自由更改而无需更新视图,并且视图无法决定显示什么。它还阻止View调用Person
上的任何额外方法,因为它没有对它的引用。
这种方法的缺点是,你失去了强大的打字和可发现性 - 很明显Person
是什么,但Tuple<int, String>
不太明显。