Как избежать вызова метода пинг-понга в MVP? - PullRequest
0 голосов
/ 30 апреля 2019

В моем приложении для Android у меня есть шаблон Fragment in MVP.Допустим, у нас есть:

  • CalculationFragment (представление)
  • CalculationPresenter (ведущий)
  • CalculationNetwork (модель)

Мне нужно многошаговое вычисление или вызов REST:

  1. В onViewCreated () класса CalculationFragment я вызываю val sessionId = presenter.firstCall() as String, чтобы получить sessionToken для дальнейшего процесса.
  2. Затем докладчик получает sessionTokenчерез ОТДЫХ.Пока все круто.Затем мне нужен следующий вызов в цепочке, который потребляет извлеченный sessionToken и NfcAdapter.getDefaultAdapter(activity).

val jsonObject = secondCall(sessionId, nfcAdapter).

Поскольку я в докладчике, у меня нет ни активности, ни NfcAdapter здесь (и я, честно говоря, не хочу).У меня здесь есть два варианта:

  1. Обход в обход В моем докладчике я возвращаюсь к своему фрагменту с sessionToken view?.onFirstCallResult(sessionToken) и сразу же вызываю из onFirstCallResult() в CalculationFragment presenter.secondCall(sessionToken, NfcAdapter.getDefaultAdapter(activity)).
  2. Короткий путь, обработанный от pesenter Я передаю активность / NfcAdapter для второго вызова в первом вызове и сохраняю его в докладчике.Мне не нужно много пинг-понг между представителем и представителем.Кроме того, я мог бы оставаться в докладчике для всех своих звонков?

Какое здесь будет элегантное решение / шаблон?

1 Ответ

0 голосов
/ 02 мая 2019

Добавьте дополнительную логику к Presenter , Модель или Command , удалив его, таким образом, из View . Обычно это лучший подход. Примите во внимание принцип Одиночной ответственности и переместите логику приложения / домена из View .

Вот несколько способов сделать это:

  • Используйте команду . Presenter будет создавать и вызывать it. Когда Command завершает работу, Presenter возвращает результаты в View .

  • Создайте Presenter , чтобы выполнять работу, как вы делали на второй диаграмме. Если докладчик прост, это нормально. Для более сложных сценариев используйте Команды , чтобы отделить ответственность за выполнение логики от ответственности , когда она должна быть вызвана .

В вашем случае вам необходимо получить NfcAdapter от View до Presenter и Command (если у вас есть один).

Вот несколько способов сделать это:

  • Передайте его в конструкторе Presenter
  • Добавьте специальный метод инициализации в Presenter и передайте все зависимости, необходимые для этого метода (public void initialize(NfcAdapter adapter, ...))
  • Добавьте метод к View , который Presenter может вызвать, чтобы получить адаптер, когда он ему нужен (NfcAdapter view.getAdapter()).
  • Передать его как параметр для вызова метода (как вы это сделали);

Выбор подхода зависит от нескольких факторов, одним из которых является вкус разработчика. Лично я бы выбрал либо метод 1, либо 2. Мне нравится инициализировать зависимости объекта (в данном случае Presenter ) в начало его жизненного цикла, если этот объект будет нужен им постоянно и они не меняются. Передайте их в вызове метода, если они меняются при каждом вызове этого метода. В этом случае я не думаю, что вы измените NfcAdapter .

Давайте создадим команду . Поскольку у вас есть довольно общее описание, а точная последовательность не описана (first_call (), second_call () слишком общие), я разработаю простую неспецифическую систему, которая выполняет пару вызовов. Я буду использовать псевдокод. Большинство вещей не являются специфическими, так как я не знаю типы возвращаемых данных и прочее.

Давайте назовем эту команду CalculateCommand . Эта команда будет использовать CalculationModel для расчета. Далее давайте определим TokenService , который будет содержать логику для получения токена (вызов API).

public class TokenService {
   public SessionToken getToken() { ... }
}

public class CalculationResult {
  // represent whatever the result is...
}

public class CalculateCommand {

    private NfcAdapter mNfcAdapter;
    private TokenService mTokenService;
    private CalculationModel mCalculationModel;

    private SessionToken mSessionToken;

    public CalculateCommand(
      NfcAdapter nfcAdapter, 
      TokenService tokenService, 
      CalculationModel calculationModel) {

      mAdapter = adapter;
      mTokenService = tokenService;
      mCalculationModel = calculatioModel;
   }

   public CalculationResult Execute() {

     startSession();

     // do more stuff if you need to 

     val result = calculate();

     return result;
  }

  private void startSession() {
     mSessionToken = mTokenService.getToken();
  }

  private Result calcualte() {
    //not sure what parameters it needs but pass them here
    return mCalculatioModel.calculate(params...);
  }
}

public class Presenter {

    private View mView;
    private NfdAdapter mAdapter;
    private CalculationModel mModel;
    private TokenService mTokenService;

    public Presenter(View view, NfdAdapter adapter) {

      mView = view;
      mNfcAdapter = adapter;
      mModel = new CalculationModel();

     // or get if from a Service Locator, DI whatever.. if you need to mock the 
     // TokenService for unittests

     mTokenService = new TokenService(); 
   }

  public void performCalculation() {

    val cmd = CalculationCommand(mAdapter, mTokenService, mModel);

    val result = cmd.execute();

    mView.setResult(result);    
 }

 public class View {

    private Presenter mPresenter;

    public View() {
       mPresenter = new Presenter(this, NfcAdapter.getDefault(activity);
    }

    public void onViewCreated() {
       mPresenter.performCalculation();
    }

    public void setResult(Result result) {
       // do something with the result
    }
}

Проверьте эти ресурсы для получения дополнительной информации о MVP и его разновидностях:

https://martinfowler.com/eaaDev/uiArchs.html

https://www.martinfowler.com/eaaDev/PassiveScreen.html

https://martinfowler.com/eaaDev/SupervisingPresenter.html

...