MVP Communication between presenters?
Asked Answered
C

3

23

I have a question about how to handle communication between presenters when using MVP. Say I have two MVP-triads. One is a list of products (Triad A) and the other is some general information about the currently selected product (Triad B).

How do I tell Presenter B that that it needs to update because the selected product has changed by A? I can of course think of ways to do this, but I was wondering if there is a general convention for how to handle this.

Thanks in advance for any ideas!

Cerebrospinal answered 18/3, 2012 at 19:32 Comment(0)
J
13

The pattern itself doesn't really prescribe how to handle this.

My own preference is a message/event hub where presenters can register interest in certain events. It prevents complex dependency trees and keeps the presenters testable.

For example:

class PresenterA
{
   void HandleProductSelectionChanged(int productId)
   {
      EventHub.Publish(EventType.ProductChanged, productId);
   }
}

class PresenterB
{
    void PresenterB
    {
       EventHub.Register(EventType.ProductChanged, HandleProductChanged);
    }

    public void HandleProductChanged(object state)
    {
       var productId = (int)state;
       var productDetails = LoadProductDetails(productId);
       view.DisplayProductDetails(productDetails);
    }
}

EventHub would keep a list of subscribers to invoke for each event type.

You retain your testability - simply call on HandleProductChanged to see how PresenterB would respond to a new product selection.

The only disadvantage (as with any pattern) is you introduce a level of indirection. If PresenterA directly invoked PresenterB, or PresenterB listened to an event on PresenterA, it is immediately obvious what's going to happen.

In this approach, you would have the extra step seeing EventType.ProductChanged, and then finding which Presenters registered an interest in that event.

In my own experience, that single level of indirection is well worth modularity you get.

Johnajohnath answered 19/3, 2012 at 0:11 Comment(1)
This is exactly what I was looking for, looks a lot better than passing presenter references around. I'll have a look at this tomorrow when I'm not as tired. Thanks.Cerebrospinal
T
3

Personally i disagree the way many people choose event bus to solve this kind of problems

It's hard for me to imagine a case when two presenters need to communicate each other, can you provide a real case?

In my opinion if two presenters need to communicate each other then you should merge these two in just one single presenter. Remember that also communication of models object between two use cases is business logic so maybe the scope of the presenter is bigger than you thought initially.

Consider also that if you use collaborators in the right way then you don't need communication between presenters. Data should be provided by collaborators.

Tarver answered 10/2, 2017 at 23:59 Comment(3)
Hi, Can you throw some light on how should one communicate from model to presenter so that presenter could perform some action on view. for eg, say, database read is done in model then, how should model tell to presenter that it has read the data and pass back the data to presenter so that presenter could update view.Monolingual
"database read is done in model"... naat XD ... i'd prefer to create an interactor.Tarver
"In my opinion if two presenters need to communicate each other then you should merge these two in just one single presenter" makes no sense. What if your feature which has presenter and view should be included in multiple places?!Erysipeloid
K
1

I'd like to add my point of view, coming with a mobile development background.

It seems to me that you are working with a typical Master-Detail scenario. What I would suggest is that despite the fact those containers A and B have their own presenters, because obviously they may have their own implementation scopes that needs to be handled in a clean way, they shouldn't directly talk to each other. They may live without each other. However if there is a way to present them at the same time - it would be done through a bigger container that handles them. And this is a key to your problem.

Declare interfaces that inform about the container A/B changes. Implement them within bigger container (let's call it host) and create a listener that will represent those interfaces to bind the communication.

Whenever there is a change in container A it informs host through interface, host passes the event to it's own presenter which can run a bigger scope operation like storing the state or sending analytic event to backend and finally it tells host to update the detail where the container B is given the data for update.

The solution with events is probably very tempting to use, I've done it myself many times, but it comes with a price. If you misuse it you'll just add to technical debt. I would suggest using this mechanism for situations where the "event" is not necessarily bound to any particular handling scenario, but may become a point of interest of other modules that live within your project.

Kyliekylila answered 19/11, 2020 at 3:27 Comment(1)
This answer spoke to my situation best. I am creating reusable user controls in a Windows Forms app. Originally I had one presenter for the main form, but it got huge, so I began splitting it up into presenters for the user controls on the form. I also have the aforementioned Event mechanism in place for internal library functions within the app--your answer saved me from using it inappropriately.Achates

© 2022 - 2024 — McMap. All rights reserved.