开发者

In MVP, should a form get the object it's going to display in the constructor?

开发者 https://www.devze.com 2023-02-22 12:23 出处:网络
It\'s my first attempt at MVP, so please be patient :) In order to present a certain entity, I\'m creating a view and a presenter.

It's my first attempt at MVP, so please be patient :)

In order to present a certain entity, I'm creating a view and a presenter.

I need to pass this entity to the view and the presenter somehow.

Is this the right way of doing it, in terms of passing around the DTO, or is there a smell?

class CustomerView
{
    public CustomerView(IPersenterProvider presenterProvider, 
                        CustomerDto customer)
    {
        _presenter = presenterProvider.ResolvePresenter<CustomerPresenter>(this);
        _presenter.Customer = customer;
    }
    ...
}

class CustomerPresenter
{
    public CustomerDto Customer
开发者_开发知识库    {
        set 
        { 
            // Show customer details in the View
        }
    }
    ...
}


I'm patient, really. You have a smell or two or three, indeed. The biggest one being the set-only property Customer on CustomerPresenter. The second one is that the view knows about the presenter - it really doesn't need to. The third one is that the view knows about the DTO on the same level as it knows about the presenter. It shouldn't - the presenter should tell the view what data to show.

This is one of my humble takes on MVP and your specific issues.

First, anything that a user can interact with, or just be shown, is a view. The laws, behavior and characteristics of such a view is described by an interface. That interface can be implemented using a WinForms UI, a console UI, a web UI or even no UI at all (usually when testing a presenter) - the concrete implementation just doesn't matter as long as it obeys the laws of its view interface.

Second, a view is always controlled by a presenter. The laws, behavior and characteristics of such a presenter is also described by an interface. That interface has no interest in the concrete view implementation as long as it obeys the laws of its view interface.

Third, since a presenter controls its view, to minimize dependencies there's really no gain in having the view knowing anything at all about its presenter. There's an agreed contract between the presenter and the view and that's stated by the view interface.

The implications of Third are:

  • The presenter doesn't have any methods that the view can call, but the view has events that the presenter can subscribe to.
  • The presenter knows its view. I prefer to accomplish this with constructor injection on the concrete presenter.
  • The view has no idea what presenter is controlling it; it'll just never be provided any presenter.

For your issue, the above could look like this in somewhat simplified code:

interface ICustomerView
{
    event EventHandler EditCustomerDetails;

    void Show(Customer customer);
}

class CustomerView : ICustomerView
{
    Customer customer;
    readonly Form form; 
    readonly Button editCustomerDetailsButton;        

    public event EventHandler EditCustomerDetails;

    public CustomerView()
    {
        // UI initialization.

        this.editCustomerDetailsButton.Click += delegate
        {
            var Handler = this.EditCustomerDetails;

            if (Handler != null)
            {
                Handler(this, EventArgs.Empty);
            }
        };
    }

    public void Show(Customer customer)
    {
        if (this.form.Visible)
        {
            // Update UI with new data.
        }
        else
        {
            // Initialize UI with data and then show it.
            this.form.ShowDialog();
        }
    }
}

interface ICustomerPresenter
{
    void ShowView(ICustomer customer);
}

class CustomerPresenter : ICustomerPresenter
{        
    readonly ICustomerView view;
    readonly IEditCustomerPresenter editPresenter;
    ICustomer customer;

    public ConfigurationPresenter(ICustomerView view, IEditCustomerPresenter editPresenter)
    {
        this.view = view;            
        this.view.EditCustomerDetails += delegate
        {
            this.editPresenter.ShowView(this.customer); // Edit
            this.view.Show(this.customer);              // Update
        };

        this.editPresenter = editPresenter;
    }

    public void ShowView(ICustomer customer)
    {
        this.customer = customer;
        this.view.Show(customer); // Assuming modal
        this.customer = null;
    }
}

That's a rather simplistic view (sic!) on this matter, but it'll maybe provide some hints.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号