MVP: Is it the View or the Presenter that should know of the Model?

后端 未结 4 507
名媛妹妹
名媛妹妹 2021-02-04 18:02

Relatively new to patterns, let me straight away show an example in the context of WinForms.

I have a basic MVP Passive View structure, which one should I go ahead with:

相关标签:
4条回答
  • 2021-02-04 18:21

    What's wrong if view knows model? After all UserView is made specifically for UserModel isnt it?

    Nothing. It's accepted practice in the Supervising Controller variant of the MVP pattern. The view interacts directly with the model for simple operations while more complex operations are marshalled throught the presenter. While in Passive View, everything goes through the presenter.

    Additionally, see Jeremy Miller's Build your own CAB series to get a better idea on the differences between the two approaches: Supervising Controller and Passive View.

    0 讨论(0)
  • 2021-02-04 18:24

    If it's not too much for your introduction to presentation patterns, I'd urge you to take a look at the Presenter-first variant of MVP.

    In this variant, and providing an answer to your question, the presenter knows both the model and view but only via interfaces. Neither the view, nor the model know of each other. The presenter co-ordinates each via events and methods.

    http://atomicobject.com/pages/presenter+first

    http://spin.atomicobject.com/2008/01/30/presenter-first-get-your-triads-talking/

    Example:

    Class Presenter {
        private IModel model;
        private IView view;
    
        void Presenter(IModel model, IView view) {
            _model = model;
            _view = view;
        }
    
        void Initialise() {
            // Attach handler to event view will raise on save
            _view.OnSave += HandleViewSave();
        }
    
        void HandleViewSave(){
            _model.Save(_view.GetStuffToSave());
        }
    }
    

    Very basic example but illustrates the point. The presenter is merely a conduit for communication between the view and model.

    Creating the presenter can be done with Poor Man's DI or a proper container:

    Presenter p = new Presenter(new CustomerModel(), new CustomerForm());
    

    Note that AtomicObject recommend no reference to presenter, so it actually looks like this:

    new Presenter(existingCustomerModel, existingCustomerForm);
    
    existingCustomerModel.Initialise();
    

    The fact that the model and view have scope means the presenter also stays in scope via its references... clever.

    0 讨论(0)
  • 2021-02-04 18:33

    Strictly speaking, you should have the following rules:

    1. Model does not know the View or the Presenter.
    2. View does not know the Model or the Presenter.
    3. Presenter knows both Models and Views, but only through their interfaces.

    The Presenter coordinates all communication between the Model and the View, typically by handling events that are raised by the View. So to answer your questions:

    1) Who should know of the concrete instance of model User, View or Presenter?

    Ideally, neither. The Presenter should be communicating with UserModel through an IUserModel interface. The concrete instance is injected into the Presenter (e.g. through its constructor).

    2) What will be the benefit in that case?

    The primary benefit is for automated unit testing. You can inject mock Models or Views to test units in isolation.

    3) Suppose my Model is never dependent on the View. In that case what's wrong if View knows Model? After all UserView is made to present UserModel isn't it?

    There's nothing inherently wrong with it. There are variations of MVP that support direct communication from the View to the Model, typically to take advantage of data binding. You lose some testability in exchange for not having to write the binding code from scratch.

    4) If Presenter should interact with only interfaces of Model and View, then to call model.Save in Save eventhandler, where do I get the concrete instance of Model from?

    Depedency injection, such as the simplified example shown below.

    public class SamplePresenter
    {
         public SamplePresenter(ISampleModel model, ISampleView view)
         {
              view.Saved += (sender, e) => model.Save();
         }
    }
    
    public interface ISampleModel
    {
         void Save();
    }
    
    public interface ISampleView
    {
         void Show();
         event EventHandler Saved;
    }
    
    public class Program
    {
         [STAThread]
         static void Main()
         {
              ISampleModel model = new SampleModel();
              ISampleView view = new SampleView();
              SamplePresenter presenter = new SamplePresenter(model, view);
              view.Show();
         }
    }
    
    0 讨论(0)
  • 2021-02-04 18:42

    The Presenter should know about the Model, the View should not. A presententation layer is a good idea in many user interface applications. A presentation layer is simply an adapter. It presents an interface that's easy for a user interface layer to use (i.e., it presents lots of events, bindable properties, and so on) while obscuring the underlying data layer. This makes the data layer easier to re-use.

    EDIT

    So why can't the view just talk to the model directly? It certainly can. The problem is that there is usually an impedence mismatch between the model and the view. In other words, the programming interface that's natural for the view to use does not match the interface that's natural for the model to expose. If you adapt the model to suit the view's needs, then you end up creating a strong coupling between the model and the particular type of interface you're using.

    For example, your app might be a GUI app today, but what if tomorrow you're asked to produce a version for the cloud? The events and bindable properties that are helpful for Winforms will just get in the way when you try to switch to WCF Rest. If you use a presentation layer, then adapting your code to the new environment will be much easier.

    0 讨论(0)
提交回复
热议问题