这是一个简单的示例,演示了使用MVP设计模式实现被动视图的概念。因为我们使用被动视图,所以视图不知道有关主持人的任何信息。主持人将仅订阅由视图发布的事件并相应地采取行动。
首先,我们需要为我们的视图定义一个合同。通常使用接口来实现这一点,基本上,我们希望与我们的视图具有非常松散的耦合。我们希望能够切换到不同的视图或者创建模拟视图进行单元测试。
以下是描述用于显示客户信息的简单视图的合同。
public interface ICustomerManagementView
{
void InitializeCustomers(ICustomer[] customers);
void DisplayCustomer(ICustomer customer);
event EventHandler<EventArgs<ICustomer>> SelectedCustomerChanged;
}
它暴露了一个单一的方法InitializeCustomers,该方法将用于使用模型中的对象初始化我们的视图。
我们还有一个事件SelectedCustomerChanged,它将被我们的Presenter用于接收通知,以表明视图中发生了某个操作。
一旦我们拥有了合同,就可以在Presenter中开始处理这些交互。
public class CustomerManagementPresenter
{
private ICustomer _selectedCustomer;
private readonly ICustomerManagementView _managementView;
private readonly ICustomerRepository _customerRepository;
public CustomerManagementPresenter(ICustomerManagementView managementView, ICustomerRepository customerRepository)
{
_managementView = managementView;
_managementView.SelectedCustomerChanged += this.SelectedCustomerChanged;
_customerRepository = customerRepository;
_managementView.InitializeCustomers(_customerRepository.FetchCustomers());
}
private void SelectedCustomerChanged(object sender, EventArgs<ICustomer> args)
{
if(_selectedCustomer != args.Value)
{
_selectedCustomer = args.Value;
_managementView.DisplayCustomer(_selectedCustomer);
}
}
}
在演示文稿中,我们可以使用另一种设计模式
依赖注入来提供对视图和任何可能需要的模型类的访问。在此示例中,我有一个CustomerRepository负责获取客户详细信息。
在构造函数中,我们有两个重要的代码行,首先我们已经订阅了视图中的SelectedCustomerChanged事件,在这里我们可以执行相关操作。其次,我们使用来自存储库的数据调用了InitializeCustomers。
此时我们实际上还没有为视图定义具体实现,我们所要做的就是创建一个实现
ICustomerManagementView的对象。例如,在Windows Forms应用程序中,我们可以执行以下操作
public partial class CustomerManagementView : Form, ICustomerManagementView
{
public CustomerManagementView()
{
this.InitializeComponents();
}
public void InitializeCustomers(ICustomer[] customers)
{
}
public void DisplayCustomer(ICustomer customer)
{
}
private void CustomerTreeViewAfterSelect(object sender, TreeViewEventArgs e)
{
var customer = e.Node.Tag as ICustomer;
if(customer != null)
{
this.OnSelectedCustomerChanged(new EventArgs<ICustomer>(customer));
}
}
protected virtual void OnSelectedCustomerChanged(EventArgs<ICustomer> args)
{
var eventHandler = this.SelectedCustomerChanged;
if(eventHandler != null)
{
eventHandler.Invoke(this, args);
}
}
public event EventHandler<EventArgs<ICustomer>> SelectedCustomerChanged;
}
如果我们想要测试我们的演示逻辑,我们可以模拟我们的视图并执行一些断言。
编辑:包括自定义事件参数。
public class EventArgs<T> : EventArgs
{
private readonly T _value;
public EventArgs(T value)
{
_value = value;
}
public T Value
{
get { return _value; }
}
}