正确使用MVP模式

目前做这个产品也有一段时间了,其中MVP模式用的非常的频繁,但是很多时候没有用对,MVP模通常是这样

Model 层, IVeiw 视图接口层, View视图层, Presenter层

Model层存着业务逻辑和数据处理, Presenter 则裁决如何处理用户的请求,IView 则是把Presenter和Veiw 之间进行解耦,使Presenter可以不依赖于具体的视图, View 通过Presenter 对Model 进行访问,这是MVP与MVC模式的主要区别,在MVC中,Model可以跨过Controller直接与View交互.

下面看项目中一个错误使用案例,一个视图接口定义

    public interface ITargetWizardView : ISmartPartInfo
    {
        UltraTree GetNavigateTargetTree();
    }

上面的方法返回了一个具体的控件类型,而这个在Presenter里面需要调用的方法应该是与控件类型无关的(与控件类型产生了耦合,试想如果控件换成了另一种控件,这个方法还能用吗?),并且不应该有返回值

在<<ASP.NET MVC 4  框架揭秘>>中有这样一段话:

对于绑定到View上的数据,不应该是View从Presenter上"拉"回来的,应该是Presenter主动推给View.从消息流(或者消息交换模式)的角度来讲,不论是View向Presenter完成针对用户交互请求的通知,还是Presenter在进行交互请求处理过程中驱动View完成相应的UI操作,都是单向(One-Way)的.反应在应用程序接口上就意味着不论是定义在Presenter中被View调用方法,还是定义在IView接口中被Presenter调用的方法最好都没有返回值.如果不采用方法调用的形式,我们也可以通过事件注册的方式实现View和Presenter的交互,事件机制体现的消息流无疑是单向的.


下面看一个正确使用的例子.

有一个员工基本信息类

public class Employee
{
    public string Id
    {
        get;
        private set;
    }
    public string Name
    {
        get;
        private set;
    }
    public string Gender
    {
        get;
        private set;
    }
    public DateTime BirthDate
    {
        get;
        private set;
    }
    public string Department
    {
        get;
        private set;
    }

    public Employee(string id, string name, string gender,
                    DateTime birthDate, string department)
    {
        this.Id = id;
        this.Name = name;
        this.Gender = gender;
        this.BirthDate = birthDate;
        this.Department = department;
    }
}

下面这个类作为操作这个对象的Model

public class EmployeeRepository
{
    private static IList<Employee> employees;
    static EmployeeRepository()
    {
        employees = new List<Employee>();
        employees.Add(new Employee("001", "张三", "男", new DateTime(1981, 8, 24), "销售部"));
        employees.Add(new Employee("001", "李四", "女", new DateTime(1982, 7, 10), "人事部"));
        employees.Add(new Employee("001", "王五", "男", new DateTime(1981, 9, 21), "人事部"));
    }

    public IEnumerable<Employee> GetEmployees(string department = "")
    {
        if(string.IsNullOrEmpty(department))
        {
            return employees;
        }
        return employees.Where(e => e.Department == department).ToArray();
    }
}
下面定义一个视图的接口,接口定义了BindEmployees和BindDepartments两个方法,分别用于绑定基于部门列表的DropDownList和基于员工的列表的GridView.除些之外,还定义了一个事件DepartmentSelected,该事件会在用户选择筛选部门后点击"查询"按钮时触发,事件类型为自定义DepartmentSelectedEventArgs

public interface IEmployeeSearchView
{
    void BindEmployees(IEnumerable<Employee> employees);
    void BindDepartments(IEnumerable<string> departments);
    event EventHandle<DepartmentSelectedEventArgs> DepartmentSelected;
}

public class DepartmentSelectedEventArgs : EventArgs
{
    public string Department
    {
        get;
        private set;
    }
    public DepartmentSelectedEventArgs(string department)
    {
        this.Department = department;
    }
}
下面是作为MVP核心的Presenter类.IView接口表现为它的一个只读属性,Model也作为它的一个只读属性,两者都在它的构造函数中进行初始化

public class EmployeeSearchPresenter
{
    public IemployeeSearchView View
    {
        get;
        private set;
    }
    public EmployeeRepository Repository
    {
        get;
        private set;
    }
    public EmployeeSearchPresenter(IEmploySearchView view)
    {
        this.View = view;
        this.Repository = new EmployeeRepository();
        this.View.DepartmentSelected += OnDepartmentSelected;
    }
    public void Initialize()
    {
        IEnumerable<Employee> employees = this.Repository.GetEmployees();
        this.View.BindEmployees(employees);
        string[] departments = new string[] {"销售部", "采购部", "人事部", "IT部"};
        this.View.BindDepartments(departments);
    }
    protected void OnDepartmentSelected(object sender, DepartmentSelectedEventArgs args)
    {
        string department = args.Department;
        var employees = this.Repository.GetEmployees(department);
        this.View.BindEmployees(employees)
    }
}
下面类为一个Web页面类,它同时实现了视图接口IEmploySearchView

public partial class Default : Page, IEmployeeSearchView
{
    public EmployeeSearchPresenter Presenter
    {
        get;
        private set;
    }
    public event EventHandle<DepartmentSelectedEventArgs> DepartmentSelected;
    public Default()
    {
        this.Presenter = new EmploySearchPresenter(this);
    }
    protected void Page_Load(object sender, EventArgs e)
    {
        if(!this.IsPostBack)
        {
            this.Presenter.Initialize();
        }
    }
    protected void ButtonSearch_Click(object sender, EventArgs e)
    {
        string department = this.DropDownListDepartments.SelectedValue;
        DepartmentSelectedEventArgs eventArgs = new DepartmentSelectedEventArgs(department);
        if(null != DepartmentSelected)
        {
            DepartmentSelected(this, eventArgs);
        }
    }
    public void BindEmployees(IEnumerable<Employee> employees)
    {
        this.GridViewEmployees.DataSource = employees;
        this.GridViewEmployees.DataBind();
    }
    public void BindDepartments(IEnumerable<string> departments)
    {
        this.DropDownListDepartments.DataSource = departments;
        this.DropDownListDepartments.DataBind();
    }
}





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值