在MVP中如何在演示者和数据服务之间传输数据
本文关键字:数据 服务 传输 之间 MVP | 更新日期: 2023-09-27 18:02:37
我是MVP模式的初学者,只是想知道关于以下情况的最佳实践。
为了更好地理解,我将通过一个例子来问这个问题。假设我们有一个形式EmployeeView
, EmployeePresenter
, EmployeeModel
和一个封装GetEmployeeByID()
方法的DataService
类。对于这个演示,我使用具体类。
让我们假设现在在一个win forms应用程序中,我们想要通过ID
搜索员工,所以我们在视图中输入ID
并按search按钮。在这种情况下,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
应该总是返回一个商业模式吗?DataService
不能返回stings
或DataSets
for ex? - 演示者可以在视图上设置
_view.EmployeeName=EmployeeModel.Name;
这样的值吗?
-
第二个选项会更好,因为你的方法被称为
GetEmployeeByID
,期望Id
的参数而不是整个模型更合乎逻辑。 -
与ASP。. NET MVC在这里你不需要你的模型是一个单一的类传递给视图,所以你可以保持两个模型更好的语义结构。
-
这取决于你想要达到的目标。同样,如果您的方法被称为
GetEmployeeByID
,那么预计它将返回类型为Employee
的业务模型。你的服务可以返回"字符串或数据集",但这意味着你需要在Presenter中添加映射来将数据集映射到你的Model。 -
是的,演示者可以设置这样的值
_view.EmployeeName=EmployeeModel.Name
,你需要实现_view.EmployeeName
的set
访问修饰符来渲染文本在一些控件中,如public EmployeeName { set { // Label Control this.lblEmployeeName.Text = value; } }
在某些情况下,通过演示者设置值只会使它变得更复杂,没有任何特别的好处。在这些情况下,你可以使用监督控制器,它是MVP的一种子类型,其中一些与业务逻辑无关的基本呈现留在视图中,更复杂的逻辑在呈现者/控制器中完成。你可以在这里找到相关信息:
http://martinfowler.com/eaaDev/SupervisingPresenter.html还有另一个子类型叫做被动视图,其中视图只包含控件,呈现者负责将值传递给视图。你可以在这里阅读:
http://martinfowler.com/eaaDev/PassiveScreen.htmlEDIT:你也可以看看这个答案来简单理解这两个子类型:什么是mvp被动视图和mvp监督控制器
编辑:这是被动视图代码。我们希望能够从一种表单类型(Windows。形式,Gtk。也希望将来能够轻松地从hibernate切换到ado.net或其他东西。
我更喜欢采用固定参数的混合方法和采用搜索参数列表的通用方法。
例如,GetSomethingByID只是获取一个int作为参数,并返回一个模型。
但是当我需要搜索一个地址时(至少涉及两个表)。一种保存地址数据,如addressno。,搜索名称等。另一个表保存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>();
}
仍然有一些我们不喜欢的东西。例如,我们必须在服务中硬编码模型名。——>坏我们可能会在将来更改这一点,以生成带有静态字符串或枚举的类,以便在更改字段名时获得编译器错误。
所以第二种方法通常看起来更好。但是你仍然需要解决很多很多的搜索参数。简单ID是最简单的例子。