实例演示:SC模式的应用
为了对SC模式下的MVP,尤其是该模式下的View和Presenter之间的交互方式有一个深刻的认识,我们现在来做一个实例演示。我们采用员工查询的场景,用ASP.NET Web Forms来建立这个简单的应用。
我们先来定义员工的数据类型,Employee来表示一个员工,有5个属性:ID、姓名、性别、出生日期和部门。
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,通过如下一个简单的EmployeeRepository类型来体现。表示所有员工列表的数据通过一个静态字段来维护,而GetEmployees方法返回指定部门的员工列表。如果没有指定筛选部门或者指定的部门字符为空,该方法直接返回所有员工列表。
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("002", "李四", "女",new DateTime(1982, 7, 10), "人事部")); employees.Add(new Employee("003", "王五", "男",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(); } }
接下来我们看看作为View接口的IEmployeeView的定义。该接口定义了BindEmployees和BindDepartments两个方法,分别用于绑定基于部门列表的DropDownList和基于员工列表的GridView。除此之外,IEmployeeView接口还定义了一个事件DepartmentSelected,该事件会在用户选择了筛选部门之后单机查询按钮时触发。DepartmentSelected事件参数类型为自定义的DepartmentSelectedEventAges,属性Department表示用户选择的部门。
public interface IEmployeeView { void BindEmployees(IEnumerable<Employee> employees); void BindDepartments(IEnumerable<string> departments); event EventHandler<DepartmentSelectedEventArgs> DepartmentSelected; } public class DepartmentSelectedEventArgs : EventArgs { public string Department { get; private set; } public DepartmentSelectedEventArgs(string department) { this.Department = department; } }
作为MVP三角关系核心的Presenter通过EmployeePresenter表示。里面包含两个属性,一个代表View的只读属性IEmployeeView接口 的View,而另一个代表Model的只读属性EmployeeRepository对象的Repository,两个属性均在构造函数中初始化。
public class EmployeePresenter { public IEmployeeView View { get; private set; } public EmployeeRepository Repository { get; private set; } public EmployeePresenter(IEmployeeView 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); } }
我们在构造函数中注册了View的DepartmentSelected事件,作为事件处理器的OnDepartmentSelected方法通过调用Repository(即Model)得到了用户选择部门下的员工列表,并且绑定到了View上。
下面我们来看看View的Web页面。
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>员工管理</title> <link rel="stylesheet" href="Content/bootstrap.css" /> <link rel="stylesheet" href="Content/site.css" /> </head> <body> <form id="form1" runat="server"> <div id="page"> <div class="text-center"> <asp:DropDownList ID="DropDownListDepartments" runat="server" CssClass="form-inline" /> <asp:Button ID="ButtonSearch" runat="server" Text="查询" OnClick="ButtonSearch_Click" CssClass="btn-primary" /> </div> <asp:GridView ID="GridViewEmployees" runat="server" AutoGenerateColumns="false" Width="100%" CssClass="table table-bordered"> <Columns> <asp:BoundField DataField="Name" HeaderText="姓名" /> <asp:BoundField DataField="Gender" HeaderText="性别" /> <asp:BoundField DataField="BirthDate" HeaderText="出生日期" DataFormatString="{0:dd/MM/yyyy}" /> <asp:BoundField DataField="Department" HeaderText="部门"/> </Columns> </asp:GridView> </div> </form> </body> </html>
下面是Web页面的后台代码定义,他实现了定义在IEmployeeView接口的方法和事件。
public partial class Default : System.Web.UI.Page, IEmployeeView { public EmployeePresenter Presenter { get; private set; } public event EventHandler<DepartmentSelectedEventArgs> DepartmentSelected; public Default() { this.Presenter = new EmployeePresenter(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(); } }