我是MVP模式的初学者,只想了解以下案例的最佳做法。
为了更好地理解,我将通过一个例子提出问题。假设我们有一个表单EmployeeView
,EmployeePresenter
,EmployeeModel
和一个DataService
类,它封装了GetEmployeeByID()
方法。在本演示中,我使用了具体的类。
让我们说,现在在win表单应用中,我们希望按ID
搜索员工,因此我们在视图中输入ID
并按“搜索”按钮。在这种情况下,Presenter
可能会使用反射来更新EmployeeModel
。 (目前只有' EmployeeModel.ID
'属性有数据)。然后Presenter
将与DataService
对话。这可以通过两种方式完成
Model
传递给DataService
,然后它会更新相同的模型并返回Presenter
。类EmployeePresenter {
private void SearchEmployee (Object sender, EventArgs e)
{
SearchEmployee();
}
private void SearchEmployee()
{
var EmployeeModel = DataService.GetEmployeeByID(EmployeeMode);
base.SetViewPropertiesFromModel(EmployeeModel);
}
}
类DataService {
public EmployeeModel GetEmployeeByID(EmployeeModel employee)
{
//Database code here
employee.Name= (string) dataReader["name"];
.
.
.
return employee;
}
}
Model
的属性值,然后DataService
将创建Model
并返回Presenter
。类EmployeePresenter {
private void SearchEmployee (Object sender, EventArgs e)
{
SearchEmployee();
}
private void SearchEmployee()
{
var EmployeeModel = DataService.GetEmployeeByID(EmployeeMode.ID);
Base.SetViewPropertiesFromModel(EmployeeModel);
}
}
类DataService {
public EmployeeModel GetEmployeeByID (string employeeID)
{
//Database code here
return new BankAccount
{
EmployeeName = (string) dataReader["name"],
.
.
. };
}
}
EmployeeSalary
?如果它的两个型号我们需要两个演示者吗?DataService
是否应始终返回商业模式? cant DataService
返回stings
或DataSets
为ex?_view.EmployeeName=EmployeeModel.Name;
?答案 0 :(得分:2)
第二个选项会更好,因为您的方法被称为GetEmployeeByID
,期望Id
的参数不是整个模型更合乎逻辑。
与ASP.NET MVC不同,您不需要将模型作为传递给视图的单个类,因此您可以保留2个模型以获得更好的语义结构。
这取决于您要实现的目标。同样,如果您的方法被调用GetEmployeeByID
,则应该返回类型为Employee
的业务模型。您的服务可以返回“字符串或数据集”,但这意味着您需要在Presenter中使用其他映射来将数据集映射到模型。
是的,演示者可以设置像_view.EmployeeName=EmployeeModel.Name
这样的值来实现set
的{{1}}访问修饰符,以便在某些控件中呈现文字,例如
_view.EmployeeName
在某些情况下,虽然通过演示者设置值只会使其更复杂而没有任何特别的好处。在这些情况下,您可以使用监督控制器,它是MVP的子类型,其中一些与业务逻辑无关的基本渲染留在视图中,更复杂的逻辑在演示者/控制器中完成。你可以在这里找到相关的信息:
http://martinfowler.com/eaaDev/SupervisingPresenter.html
还有另一个名为Passive View的子类型,其中视图仅包含Controls,Presenter负责将值传递给View。你可以在这里阅读:
http://martinfowler.com/eaaDev/PassiveScreen.html
编辑:您还可以查看此答案,以便简要了解这两种子类型: What are MVP-Passive View and MVP-Supervising controller
答案 1 :(得分:0)
编辑: 这是被动视图代码。 我们希望能够从一种表单类型(Windows.Forms,Gtk.Forms等)切换到另一种表单类型,并希望能够在将来轻松地从hibernate切换到ado.net或其他类型。
我更喜欢采用固定参数的混合方法和采用搜索参数列表的通用参数。
例如,GetSomethingByID只会将一个int作为参数并返回一个Model。
但是当我想搜索一个地址时(至少有两个表被调用)。一个保存地址数据,如addressno。,searchname等。还有另一个包含name1,name2等的表。然后我会得到一个带有大量参数的方法。 在这一点上,我没有扩展这两个表中的任何一个。(!)
我们不喜欢超过4个参数的方法。所以我们创建了一个" QueryMethodParameter"我们从视图中使用的对象。 我将举一个例子,我表现出来比解释我们做的更容易。
当您在我们的视图中搜索地址时,会执行此操作。
p.Items.Add(new QueryMethodParameterItem("Address", "AddressNumber", addressNumber));
p.Items.Add(new QueryMethodParameterItem("Address", "Searchname", searchName));
p.Items.Add(new QueryMethodParameterItem("MailingAddress", "Name1", name1));
p.Items.Add(new QueryMethodParameterItem("MailingAddress", "Name2", name2));
p.Items.Add(new QueryMethodParameterItem("MailingAddress", "Name3", name3));
p.Items.Add(new QueryMethodParameterItem("MailingAddress", "Street", street));
p.Items.Add(new QueryMethodParameterItem("MailingAddress", "Zipcode", zipcode));
p.Items.Add(new QueryMethodParameterItem("MailingAddress", "Location", location));
((AddressSearchPresenter)this.Presenter).DoAddressSearch(p);
AddressSearchPresenter
public void DoAddressSearch(QueryMethodParameter p)
{
IAddressService addrService = (IAddressService)ApplicationController.GetInstance().ServiceFactory.GetService(typeof(Model.Address), this.ServiceContext);
IListEx<Model.Address> erg = addrService.LoadAddresses(p);
this.SetModel(erg);
_viewItems = new AddressSearchViewItems(erg);
this.ModelToView();
}
AddressService
public IListEx<Model.Address> LoadAddresses(QueryMethodParameter p)
{
ICriteria ca = this.ServiceFactory.CreateCriteria(this.Context, typeof(Model.Address));
ICriteria ma = null;
for (int i = 0; i < p.Items.Count; i++)
{
object val = p.Items[i].Value;
if (val == null)
{
throw new NullReferenceException();
}
if (val.GetType() == typeof(string))
{
if (!val.ToString().EndsWith("%"))
{
val = val.ToString() + "%";
}
if (!val.ToString().StartsWith("%"))
{
val = "%" + val.ToString();
}
}
if (p.Items[i].ModelName == "Address")
{
ca.Add(Expression.Like(p.Items[i].PropertyName, val));
}
else if (p.Items[i].ModelName == "MailingAddress")
{
if (ma == null)
{
ma = ca.CreateCriteria("MailingAddress", "MailingAddress");
}
ma.Add(Restrictions.Like(p.Items[i].ModelName + "." + p.Items[i].PropertyName, val));
}
else
{
throw new NotImplementedException();
}
}
ca.Add(Expression.Gt("AddressID", 0));
return ca.ListEx<Model.Address>();
}
还有一些我们不喜欢的东西。例如,我们在服务中对模型名称进行硬编码。 - &GT;坏 我们将来可能会使用静态字符串或枚举来更改此类,以便在更改字段名称时获得编译器错误。
所以第二种方法总体上看起来更好。但是您仍然需要针对许多搜索参数的解决方案。简单的ID就是最简单的例子。