GWT:使用分离的 mvp 构建小部件

发布于 2024-12-05 13:10:42 字数 517 浏览 1 评论 0 原文

我正在尝试构建一个具有分离模型、视图和演示器的 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 架构?

I'm trying to build a gwt widget with separated model, view and presenter.

I'm using just one class for all of these components so far:

A compact example:

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);
  }
}

In my appreciation the information "selectedCell" (and in my project many other data) should be stored in a separate model.
How can I implement this structurally correct, so it still is a widget but with an encapsulated mvp architecture?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

新一帅帅 2024-12-12 13:10:42

在我的一个项目中,我被要求设计一个旋转器项目,该项目在移动网络应用程序上看起来很好。然后我们意识到我们实际上需要我们的旋转器的另一种视图,它也“更薄”。因此,我尝试将 MVP 方法应用于我的小部件实现,这对我来说效果很好。下面这个例子是一个非常简单的例子,不适合生产使用,只是为了演示。

按照 MVP 模式定义一个 Presenter 和一个 View 接口。这里的重点是使视图实现变得愚蠢,以便可以轻松地切换它们。请注意,Spinner 实际上并不是一个 Widget,但它实现了 IsWidget,这意味着它将被视为一个 widget,但实际上我们将传递视图实现的引用。

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);

现在,如果我想更改微调器项目的外观、更改方向、也许添加用于旋转的精美动画等,我只需要更改我的视图实现。最后但并非最不重要的一点是,当涉及到测试我的小部件时,这种方法将有所帮助,因为我可以轻松地模拟我的视图。

In one of my projects I was asked to design a spinner item which is dressed to look good on a mobile web app. Then we realized we actually need another view for our spinner which is 'thinner' as well. So I have tried to aplly the MVP approach to my widget implementation which worked well for me. This one below is a very simple example not for production use just for the sake of demonstration

Define a Presenter and a View interface as in MVP pattern. The point here is to make the view implementations dumb so they can be switched without a hassle. Note that Spinner is not actually a Widget but it implements IsWidget which means it will be treated like a widget but in fact we will be passing the reference of our view implementation.

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();
    }
}

And the view Implementation itself which implements the view interface defined in Spinner class. Notice how we delegate user events to Spinner class to be handled over the SpinnerPresenter interface.

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 interface :

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

Finally to add my widget to rootpanel. Notice I can add spinner class as if it was a widget

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

Now if i wanted to change the way my spinner item looks, change orientation, maybe add a fancy animation for spinning etc, I need only to change my View Implementation. Last but not least when it comes to testing my widget this approach will help since I can easily mockup my view.

甲如呢乙后呢 2024-12-12 13:10:42

仅供参考,GWT 中的单元小部件是在内部使用 MVP 构建的。 CellList(例如)是“视图”部分,并实例化一个内部演示者。

另外,Google I/O 2010 的这次会议也让我大开眼界:http://www.google.com/events/io/2010/sessions/gwt-continuous-build-testing.html

FYI, the cell widgets in GWT are built with MVP internally. A CellList (for instance) is the "view" part and instantiates an internal presenter.

Also, this session from Google I/O 2010 was eye opening for me: http://www.google.com/events/io/2010/sessions/gwt-continuous-build-testing.html

時窥 2024-12-12 13:10:42

如果您还没有阅读以下 MVP 文章,我建议您阅读以下文章(如果您已经阅读过,请原谅我):http://code.google.com/webtoolkit/articles/mvp-architecture.html http://www.gwtproject.org/articles/mvp-architecture.html

相信我继续分离模型、视图和演示者是值得的。这个问题似乎总是很简单,可以在一堂课上解决,但当我尝试过时,我总是最终把事情分开。您会欣赏更好的关注点分离及其提供的灵活性。

I recommend you read the following MVP article if you haven't already (and forgive me if you have): http://code.google.com/webtoolkit/articles/mvp-architecture.html http://www.gwtproject.org/articles/mvp-architecture.html

Believe me it's worth it to go ahead and separate out your model, view, and presenter. The problem always seems simple enough to have in one class, but when I've tried that I always end up separating things out. You'll appreciate having a better separation of concerns and the flexibility it offers.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文