简体   繁体   English

如何在MVP中的演示者和数据服务之间传输数据

[英]How to transfer data between presenter and data service in MVP

I'm a beginner to MVP pattern and just want to know the best practices with regard to the following case. 我是MVP模式的初学者,只想了解以下案例的最佳实践。

For better understanding I'll ask the question by an example. 为了更好地理解,我将通过一个例子提出问题。 Lets say we have a form EmployeeView , EmployeePresenter , EmployeeModel and a DataService class which encapsulates GetEmployeeByID() method. 假设我们有一个表单EmployeeViewEmployeePresenterEmployeeModel和一个封装GetEmployeeByID()方法的DataService类。 For this demonstration I use concrete classes. 在本演示中,我使用了具体的类。

Lets say now in a win forms app we want to search employees by ID , so we enter ID in the view and press Search button. 让我们说,现在在win表单应用程序中,我们希望按ID搜索员工,因此我们在视图中输入ID并按“搜索”按钮。 In this event the Presenter will update the EmployeeModel probably using reflection. 在这种情况下, Presenter可能会使用反射更新EmployeeModel (at this moment only ' EmployeeModel.ID ' property has data). (此时只有' EmployeeModel.ID '属性有数据)。 Then the Presenter will talk to DataService . 然后, Presenter将与DataService This can be done in two ways 这可以通过两种方式完成

  1. Here we pass the Model to DataService and it will then update the same model and return back to the Presenter . 在这里,我们将Model传递给DataService ,然后它将更新相同的模型并返回到Presenter

class EmployeePresenter { class EmployeePresenter {

private void SearchEmployee (Object sender, EventArgs e)
{
    SearchEmployee();
}

private void SearchEmployee()
{
    var EmployeeModel = DataService.GetEmployeeByID(EmployeeMode);
    base.SetViewPropertiesFromModel(EmployeeModel);
}

} }

class DataService { class DataService {

public EmployeeModel GetEmployeeByID(EmployeeModel employee)
{
    //Database code here

    employee.Name= (string) dataReader["name"];
    . 
    .
    .
    return employee;

}

} }

  1. Here we pass only a property value of the Model and then the DataService will create a Model and return to the Presenter . 这里我们只传递Model的属性值,然后DataService将创建一个Model并返回到Presenter

class EmployeePresenter { class EmployeePresenter {

private void SearchEmployee (Object sender, EventArgs e)
{
    SearchEmployee();
}

private void SearchEmployee()
{
    var EmployeeModel = DataService.GetEmployeeByID(EmployeeMode.ID);
    Base.SetViewPropertiesFromModel(EmployeeModel);
}

} }

class DataService { class DataService {

public EmployeeModel GetEmployeeByID (string employeeID)
{
    //Database code here

    return new BankAccount
    {
     EmployeeName = (string) dataReader["name"],
     .
     .
     . };
}

} }

  1. Which one of the above is acceptable? 以上哪一项是可以接受的?
  2. For example if details of two entities (say, employee and salary entities) are shown on a single view, do we consider these entities as two models or as a single model like EmployeeSalary ? 例如,如果在单个视图上显示两个实体(例如,员工和工资实体)的详细信息,我们是将这些实体视为两个模型还是像EmployeeSalary这样的单个模型? If its two models do we need two presenters? 如果它的两个模型我们需要两个演示者吗?
  3. Should DataService always return a business model? DataService应该总是返回业务模型吗? cant DataService return stings or DataSets for ex? 倾斜DataService返回stingsDataSets为前?
  4. Can presenter set values on the view like _view.EmployeeName=EmployeeModel.Name; Presenter可以在视图上设置值,如_view.EmployeeName=EmployeeModel.Name; ?
  1. The second option would be better as your method is called GetEmployeeByID it is more logical to expect a parameter of Id not a whole model. 第二个选项会更好,因为您的方法称为GetEmployeeByID ,期望Id的参数不是整个模型更合乎逻辑。

  2. Unlike ASP.NET MVC here you do not require your model to be a single class passed to the view so you can keep 2 models for better semantic structure. 与ASP.NET MVC不同,您不需要将模型作为传递给视图的单个类,因此您可以保留2个模型以获得更好的语义结构。

  3. This depends on what you are trying to achieve. 这取决于你想要达到的目标。 Again if your method is called GetEmployeeByID it is expected to return a business model of type Employee . 同样,如果您的方法名为GetEmployeeByID返回Employee类型的业务模型。 Your service can return "strings or data sets" but that would mean you would need additional mapping in the Presenter to map the data set to your Model. 您的服务可以返回“字符串或数据集”,但这意味着您需要在Presenter中使用其他映射来将数据集映射到模型。

  4. Yes the presenter can set values like this _view.EmployeeName=EmployeeModel.Name you would need to implement the set access modifier of _view.EmployeeName to render text in some control like 是的,演示者可以设置像_view.EmployeeName=EmployeeModel.Name这样的值,您需要实现_view.EmployeeNameset访问修饰符,以在某些控件中呈现文本,如

     public EmployeeName { set { // Label Control this.lblEmployeeName.Text = value; } } 

In some cases though setting values trough the presenter just makes it more complex without any particular benefits. 在某些情况下,虽然通过演示者设置值只会使其更复杂而没有任何特别的好处。 In these cases you can user Supervising Controller which is a sub type of MVP where some basic rendering that is not related to the business logic is left in the View and more complex logic is done in the Presenter/Controller. 在这些情况下,您可以使用监督控制器,它是MVP的子类型,其中一些与业务逻辑无关的基本渲染留在视图中,更复杂的逻辑在演示者/控制器中完成。 You can find information about it here: 您可以在此处找到有关它的信息:

http://martinfowler.com/eaaDev/SupervisingPresenter.html http://martinfowler.com/eaaDev/SupervisingPresenter.html

There is also another sub type called Passive View where the view only holds Controls and the Presenter is responsible for passing values to the View. 还有另一个名为Passive View的子类型,其中视图仅包含Controls,Presenter负责将值传递给View。 You can read about it here: 你可以在这里读到它:

http://martinfowler.com/eaaDev/PassiveScreen.html http://martinfowler.com/eaaDev/PassiveScreen.html

EDIT: You can also look at this answer for a brief understanding of both sub types: What are MVP-Passive View and MVP-Supervising controller 编辑:你也可以看看这个答案,简要了解这两个子类型: 什么是MVP-Passive View和MVP-Supervising控制器

EDIT: This is passive view code. 编辑:这是被动视图代码。 We want to be able to switch from one Form Type (Windows.Forms, Gtk.Forms, etc.) to another and also want to be able to easily switch from hibernate to ado.net or something else in the future. 我们希望能够从一种表单类型(Windows.Forms,Gtk.Forms等)切换到另一种表单类型,并希望能够在将来轻松地从hibernate切换到ado.net或其他东西。

I would prefer a mix methods who take fixed parameters and generic ones which taking a list of search parameters. 我更喜欢采用固定参数的混合方法和采用搜索参数列表的通用参数。

For example GetSomethingByID just would get one int as a parameter and return a Model. 例如,GetSomethingByID只需要一个int作为参数并返回一个Model。

But when I want so search an address (at least two tables are involed). 但是当我想要搜索一个地址时(至少有两个表被调用)。 One which holds address data like addressno., searchname and so on. 一个保存地址数据,如addressno。,searchname等。 And another table which holds name1, name2, etc. Then I would get a method with an horrible amount of parameters. 还有另一个包含name1,name2等的表。然后我会得到一个带有大量参数的方法。 And at this point I'm not extending any of the two tables.(!) 在这一点上,我没有扩展这两个表中的任何一个。(!)

We don't like methods with more than 4 parameters. 我们不喜欢超过4个参数的方法。 So we created a "QueryMethodParameter" object which we use from our views. 所以我们创建了一个“QueryMethodParameter”对象,我们在视图中使用它。 I will give an example, it's easier for me to show than to explain what we do. 我举一个例子,我更容易展示而不是解释我们做什么。

This is executred when you search an address in our view. 当您在我们的视图中搜索地址时,会执行此操作。

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

There're still some things we don't like. 还有一些我们不喜欢的东西。 For example we've to hardcode Modelnames in our Service. 例如,我们要在我们的服务中对模型名进行硬编码。 --> Bad We'll possible change this in the future to generated classes with static strings or enums, to get compiler errors when a field name is changed. - > Bad我们可能会在将来更改为使用静态字符串或枚举生成类,以便在更改字段名称时获得编译器错误。

So the second approach in general looks better. 所以第二种方法总体看起来更好。 But you still need a solution for many, many search parameters. 但是您仍然需要针对许多搜索参数的解决方案。 A simple ID is the simplest example. 一个简单的ID是最简单的例子。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM