简体   繁体   中英

Observer Pattern in MVP

I have a System (game) which I try to implement using the architecture Model-View-Presenter. What I have done right now is a while loop in the presenter that calls continuously the view methods for displaying. The way I do this is using a Producer/Consumer pattern, where the View register and event handler for touch events(Android) and produce the corresponding touch imstances, that the presenter consumes in the while loop.

Now I would like to use the pattern Observer/Suscriber between The Model and the Presenter. Using this the Presenter will be the Observer subscribe to changes on the state of the Model. The thing is, the presenter will execute the updates in the model, accordingly to the events occurred in the view. Every time that the presenter executes one method in.the model, It will be. possible to change its state and notify the presenter. I will separate then in another thread the model for every update, but how can I notify the presenter if this is running in a different thread inside a while loop? If I call the method notify observers, when the presenter will call the corresponding method?

Its driving me crazy! :PI need your help captains!

It's possible you are over engineering this in terms of architecture. MVP and Producer/Consumer and Observable all in the same post. Alarm bells are ringing. I suspect that you don't need the producer/consumer or the observer pattern, MVP is probably totally adequate.

Try this.

Create 3 files:

  • GameFragment.java
  • GameView.java
  • GamePresenter.java

GamePresenter:

public class GamePresenter {
    private final GameView view;

    public GamePresenter(GameView view){
        this.view = view;
        NetworkController.addObserver(this);//listen for events coming from the other player for example. 
    }

    public void onSwipeRight(){
        // blah blah do some logic etc etc
        view.moveRight(100);
        NetworkController.userMovedRight();
    }

    public void onNetworkEvent(UserLeftGameEvent event){
        // blah blah do some logic etc etc
        view.stopGame()
    }
}

GameView

is an interface

public interface GameView {
    void stopGame();
    void moveRight(int pixels);
}

GameFragment is a class that extends Fragment and implements GameView AND has a GamePresenter as a member.

public class GameFragment extends Fragment implements GameView {
    private GamePresenter presenter;

    @Override
    public void onCreate(Bundle savedInstanceState){
        presenter = new GamePresenter(this);
    }
}

The key to this approach is to clearly understand the role of each file.

The Fragment is in control of anything view related (Buttons, TextView etc). It informs the presenter of user interactions.

The Presenter is the engine, it takes the information from the View (in this case it is the Fragment, but notice that this pattern lends itself well to Dependency injection? That's no coincidence. The Presenter doesn't know that the View is a Fragment - it doesn't care) and combines it with the information it is receiving from 'below' (comms, database etc) and then commands the View accordingly.

The View is simply an interface through which the Presenter communicates with the View. Notice that the methods read as commands , not as questions (eg getViewState()) and not to inform (eg onPlayerPositionUpdated()) - commands (eg movePlayerHere(int position)).

It Doesn't matter. You have an object, Presenter , which is being used inside an infinite loop inside a thread. That does not mean you cannot call it's methods while its being called by the thread as well. The only consideration you have to take care of is that, if the data being read/used by the thread is the same altered by the observer notification, you shoud synchronize it access.

So, to summarize, while the Presenter is running inside the infinite loop, any call to it's method will be answered instantly (unless they have synchronized access, in which case it will block until it gets the lock ownership)

The following is completly fine:

class Presenter implements IObserver
{
    public void aMethod() { }

    public void notifyObserver() { }
}

class Model
{
    private List<IObserver> observers = new ArrayList<>();

    public void addObserver(IObserver obs) { observers.add(obs); }

    public void notifyObservers()
    {
        for(IObserver o : observers) { o.notifyObserver(); }
    }
}


final Presenter myPresenter = new Presenter();
Model myModel = new Model();
myModel.add(myPresenter);

new Thread(new Runnable() 
{
    @Override
    public void run()
    {
        while(true)
        {
            myPresenter.aMethod();
        }           
    }
).start();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM