Search code examples
design-patternsgwtmvpgwt-mvp

MVP pattern. How to reduce code repeating?


MVP pattern assumes that View expose methods to Presenter. For example in View we can write:

public HasClickhandlers getButton() {
    return myBtn;
} 

and access to this method from presenter, like

view.getButton().addclickhanlder() ...

But when I build my app in this style, I have a lot unnecessary code. For example I want to create TablesView and TablesPresenter (I decide thatTablesPresenter and TablesView is minimal entity (minimal module), that can not be divided into more small presenters and views, and can not be more complex). Then, when I create TablesView, I want to put inside this view another custom component - MyCustomTable. And Inside MyCustomTable put MyCustomHeader, inside MyCustomHeader put MyCustomFilter and so on (this sequence may be much longer)... So problem is when I want to access from Presenter to entered text(by user) inside MyCustomFilter, I need to expose method on MyCustomFilter:

//inside MyCustomFilter
public String getFilterText() {
   return textBox.getText();
}

then in widget that contains MyCustomFilter - i.e. in MyCustomHeader I need to expose this method:

//inside MyCustomHeader
public String getFilterText() {
  return myCustomFilter.getFilterText();
}

after it, inside MyCustomTable I need to expose this method:

//inside MyCustomTable
public String getFilterText() {
  return myCustomHeader.getFilterText();
}

After it I need to expose getFilterText() method inside TablesView (that contains MyCustomTable) and after all this operations my presenter can access to text inside MyCustomFilter.. And sometime this sequence is more longer. So how to solve this problem? May be I not understand some things about MVP?


Solution

  • One way to solve it would be the use of interfaces. By that you could expose a view of your components without creating a tight coupling between the view and the presenter.

    Something along these lines:

    public interface CustomFilter {
       String getFilterText();
       // other methods that might be accessed from your presenter
    }
    
    public class MyCustomFilter implements CustomFilter {
    
        @Override
        public String getFilterText() {
            return textBox.getText();
        }
    }
    

    You can do the same thing for the other componenents:

    CustomHeader:

    public interface CustomHeader {
       CustomFilter getFilter();
       // or String getFilterText()
       // other methods that might be accessed from your presenter
    }
    
    public class MyCustomHeader implements CustomHeader {
    
        @Override
        public CustomFilter getFilter() {
            return myCustomFilter;
        }
    }
    

    CustomTable:

    public interface CustomTable {
       CustomHeader getHeader();
       // or Sring getFilterText();
       // other methods that might be accessed from your presenter
    }
    
    public class MyCustomTable implements CustomTable {
    
        @Override
        public CustomHeader getHeader() {
            return myCustomHeader;
        }
    }
    

    You can decide if you only want to expose in each interface just a String or the entire client component's interface. If you expose the entire interface you might violate the law of demeter by having calls like this in your presenter:

    getView().getTable().getHeader().getFilter().getFilterText(). 
    

    Probably a better solution would be to define Strings in your interfaces which delegate the calls up the hierarchy to the your CustomFilter interface: getView().getTable().getFilterText(); or even getView().getFilterText().

    The other benefits of using interfaces is that you can easily mock them for Unit testing your presenters and even view components in isolation and you can easily create an switch between different implementations of your UI components (for example one that is optimized for smartphones, etc) without changing anything in your Presenters