GWT: создание виджетов с разделенным MVP - PullRequest
0 голосов
/ 20 сентября 2011

Я пытаюсь создать виджет gwt с разделенными моделью, видом и презентатором.

Пока что я использую только один класс для всех этих компонентов:

Компактный пример:

public class MyCellSelectableTable extends Composite {

   private WhatEverRepresentation selectedCell;

   public MyCellSelectableTable() {

      Grid myTable = new Grid(2,2);
      /*
       * Some code to realize a table with cell selection
       * ...
       */

     initWidget(myTable);
  }
}

По моему признанию, информация "selectedCell" (и в моем проекте много других данных) должна храниться в отдельной модели. Как я могу реализовать это структурно правильно, чтобы это все еще был виджет, но с инкапсулированной архитектурой mvp?

Ответы [ 3 ]

2 голосов
/ 20 сентября 2011

В одном из моих проектов меня попросили спроектировать спиннер, который будет выглядеть так, чтобы он хорошо смотрелся в мобильном веб-приложении.Затем мы поняли, что нам на самом деле нужен другой вид для нашего счетчика, который также «тоньше».Поэтому я попытался применить MVP-подход к реализации моего виджета, который мне помог.Ниже приведен очень простой пример не для производственного использования, просто для демонстрации

Определите интерфейс Presenter и View, как в шаблоне MVP.Смысл здесь в том, чтобы сделать реализации представлений немыми, чтобы их можно было без проблем переключать.Обратите внимание, что Spinner на самом деле не является виджетом, но он реализует IsWidget, что означает, что он будет обрабатываться как виджет, но на самом деле мы будем передавать ссылку на нашу реализацию представления.

public class Spinner implements IsWidget, SpinnerPresenter{
    interface View{
        Widget asWidget();
        void stepUp(int step);
        void stepDown(int step);
        void setValue(int value);
        void setPixelSize(int width,int height);
    }   
    View view;
    int value;  
    public Spinner() {
        view = new SpinnerImpl(this);
        view.setValue(0);
    }   
    public int getValue() {
        return value;
    }   
    public void setValue(int value) {
        if (value == this.value)
            return;
        this.value = value;
        view.setValue(value);
    }
    public void setPixelSize(int width, int height){
        view.setPixelSize(width,height);
    }
    @Override
    public void downButtonClicked() {
        value--;
        view.stepDown(1);
    }
    @Override
    public void upButtonClicked() {
        value++;
        view.stepUp(1);
    }
    @Override
    public Widget asWidget() {
        return view.asWidget();
    }
}

И сама реализация представления, котораяреализует интерфейс представления, определенный в классе Spinner.Обратите внимание, как мы делегируем пользовательские события классу Spinner для обработки через интерфейс SpinnerPresenter.

public class SpinnerImpl extends Composite implements Spinner.View{
    private TextBox txtBox;
    private Button upButton,downButton;
    private HorizontalPanel panel;
    private SpinnerPresenter presenter;
    public SpinnerImpl(SpinnerPresenter presenter){
        this.presenter = presenter;
        upButton = new Button("up");
        downButton = new Button("down");

        txtBox = new TextBox();
        txtBox.setEnabled(false);

        panel = new HorizontalPanel();
        panel.add(upButton);
        panel.add(txtBox);
        panel.add(downButton);

        addHandlers();
        initWidget(panel);      
    }   
    private void addHandlers() {
        upButton.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                presenter.upButtonClicked();
            }
        });
        downButton.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                presenter.downButtonClicked();
            }
        });     
    }
    @Override
    public void stepDown(int step) {
        txtBox.setValue(Integer.parseInt(txtBox.getValue())-1+"");
    }
    @Override
    public void stepUp(int step) {
        txtBox.setValue(Integer.parseInt(txtBox.getValue())+1+"");
    }
    @Override
    public void setValue(int value) {
        txtBox.setValue(0+"");
    }
}

Интерфейс SpinnerPresenter:

public interface SpinnerPresenter {
    void upButtonClicked();
    void downButtonClicked();
}

Наконец, чтобы добавить мой виджет в корневую панель.Обратите внимание, что я могу добавить класс прядильщика, как если бы это был виджет

Spinner s = new Spinner();
RootPanel.get().add(s);

Теперь, если я хочу изменить внешний вид моего прядильщика, изменить ориентацию, возможно, добавить необычную анимацию для прядения и т. Д., Мне нужно толькоизменить мой вид реализации.И последнее, но не менее важное, когда дело доходит до тестирования моего виджета, этот подход поможет, так как я могу легко смоделировать свой вид.

0 голосов
/ 20 сентября 2011

К вашему сведению, виджеты ячеек в GWT встроены внутри MVP. CellList (например) является частью "view" и создает экземпляр внутреннего докладчика.

Кроме того, эта сессия из Google I / O 2010 открыла мне глаза: http://www.google.com/events/io/2010/sessions/gwt-continuous-build-testing.html

0 голосов
/ 20 сентября 2011

Я рекомендую вам прочитать следующую статью MVP, если вы еще этого не сделали (и простите меня, если у вас есть): http://code.google.com/webtoolkit/articles/mvp-architecture.html http://www.gwtproject.org/articles/mvp-architecture.html

Поверьте мне, стоит пойти дальше и отделить вашу модель, вид и докладчика. Проблема всегда кажется достаточно простой, чтобы иметь ее в одном классе, но когда я пытаюсь это сделать, я всегда в конечном итоге разделяю вещи. Вы по достоинству оцените лучшее разделение интересов и гибкость, которую он предлагает.

...