Шаблон наблюдателя в MVP

У меня есть Система (игра), которую я пытаюсь реализовать с использованием архитектуры Model-View-Presenter. То, что я сделал прямо сейчас, - это цикл while в презентаторе, который постоянно вызывает методы представления для отображения. Я делаю это с помощью шаблона «Производитель / Потребитель», в котором регистр просмотра и обработчик событий для событий касания (Android) создают соответствующие экземпляры касания, которые докладчик использует в цикле while.

Теперь я хотел бы использовать шаблон Observer / Suscriber между The Model и Presenter. Используя это, Presenter будет наблюдателем, подписывающимся на изменения состояния модели. Дело в том, что ведущий будет выполнять обновления в модели в соответствии с событиями, произошедшими в представлении. Каждый раз, когда ведущий выполняет один метод в модели, он будет. можно изменить его состояние и уведомить докладчика. Затем я выделю модель для каждого обновления в другом потоке, но как я могу уведомить ведущего, если оно выполняется в другом потоке внутри цикла while? Если я вызову метод уведомления наблюдателей, когда докладчик вызовет соответствующий метод?

Это сводит меня с ума! : P Мне нужна ваша помощь, капитаны!


person CristoJV    schedule 22.04.2016    source источник


Ответы (2)


Неважно. У вас есть объект Presenter, который используется внутри бесконечного цикла внутри потока. Это не означает, что вы не можете вызывать его методы, пока он также вызывается потоком. Единственное, о чем вы должны позаботиться, это то, что если данные, читаемые / используемые потоком, совпадают с измененными уведомлением наблюдателя, вы должны синхронизировать их доступ.

Итак, чтобы подвести итог, пока Presenter работает внутри бесконечного цикла, на любой вызов его метода ответят мгновенно (если у них нет синхронизированного доступа, и в этом случае он будет заблокирован до тех пор, пока не получит право владения блокировкой)

Следующее совершенно нормально:

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();
person Nadir    schedule 22.04.2016
comment
Ооо! Вот и все! :) Дело в том, что ведущий сам запускает метод обновления в отдельном потоке, в рамках цикла while ваше решение выглядит яснее, используйте метод обновления внутри другого объекта, на котором размещен поток! Вот чего мне не хватало. Таким образом, в этом случае, если мне нужно уведомить докладчика, он сможет присутствовать на вызове, и он не будет запускать цикл. Умно, спасибо !!!! - person CristoJV; 22.04.2016

Возможно, вы переборщили с архитектурой. MVP и Producer / Consumer и Observable в одном посте. Звонят тревожные звонки. Я подозреваю, что вам не нужен шаблон производителя / потребителя или наблюдателя, MVP, вероятно, полностью подходит.

Попробуй это.

Создайте 3 файла:

  • 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

это интерфейс

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

GameFragment - это класс, который расширяет Fragment и реализует GameView И имеет GamePresenter в качестве члена.

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

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

Ключом к этому подходу является четкое понимание роли каждого файла.

Фрагмент контролирует все, что связано с представлением (кнопки, TextView и т. д.). Он информирует докладчика о взаимодействиях с пользователем.

Presenter - это движок, он берет информацию из View (в данном случае это фрагмент, но обратите внимание, что этот шаблон хорошо подходит для внедрения зависимостей? Это не совпадение. Presenter не знайте, что представление - это фрагмент - это не волнует) и объединяет его с информацией, которую он получает «снизу» (связь, база данных и т. д.), а затем, соответственно, командами представления.

Представление - это просто интерфейс, через который докладчик взаимодействует с представлением. Обратите внимание, что методы читаются как команды, не как вопросы (например, getViewState ()) и не для сообщить (например, onPlayerPositionUpdated ()) - команды (например, movePlayerHere (int position)).

person shredder    schedule 22.04.2016
comment
Оооо, о чем я думал, так это об использовании первого шаблона "Производитель / Потребитель" для связи между представлением и ведущим. Но если я хочу, чтобы докладчик был полностью отделен от модели, модель не должна ничего знать о докладчике, поэтому я думал о сохранении контракта в формате событий, которые модель будет использовать для передачи своего состояния докладчику, чтобы ведущий может соответственно обновить представление :). Таким образом, докладчик запускает цикл while, получает события от представления, обновляет модель, обновляет представление и т. Д. Как вы думаете, это плохая реализация - person CristoJV; 22.04.2016