0

I am implementing the frontend of an application in GWT (see attached picture) and I have view class which is getting bigger as more widgets are added to the frontend. enter image description here As stated in GWT tutorial, the view class must implement the Display interface of the presenter class. y problem is I have a lot a methods in that interface and as I implement them in the view class, it becomes too big. That's why I would like to refactor the code to reduce the size of the view class by implementing those methods in others classes and reference them where needed in the view class;for instand by grouping them per group box (one class per group box).

Below is a sample code: Note that in the real application we have more widgets per group box. The problem I am facing will be well explained as you read through the whole posting because I will be adding more details.

code to be refactored:

ContactPrewsenter.java

public class ContactPresenter {

public interface Display
{
    void methodA();
    void methodB();
    void methodC();
    void methodD();
    void methodE();
    void methodF();
    .
    .
    .
    void methodM();
}

public ContactPresenter()
{
    //Some stuff here
}
......
......

@Override
public void bind(){
        //Some stuff here
    }

 }

ContactView.java:

    public class ContactView  implements ContactPresenter.Display
{
    private final Listbox listBoxA;
    private final Listbox listBoxB;
    private final Listbox listBoxC;
    private final Listbox listBoxD;
    private final Listbox listBoxE;
    private final Listbox listBoxF;
    private final Listbox listBoxG;
    private final Listbox listBoxH;
    private final Listbox listBoxI;
    private final Listbox listBoxJ;
    private final Listbox listBoxK;
    private final Listbox listBoxL;
    private final Listbox listBoxM;

    public ContactView()
    {

        listBoxA = new ListBox();
        listBoxB = new ListBox();

        VerticalPanel vPanel1= new VerticalPanel();
        vPanel1.add(listBoxA);
        vPanel1.add(listBoxB);

        GrooupBox groupBox1 = new GroupBox();
        groupBox1.add(vPanel1);


        listBoxC = new ListBox();
        listBoxD = new ListBox();

        VerticalPanel vPanel2 = new VerticalPanel();
        vPanel2.add(listBoxC);
        vPanel2.add(listBoxD);

        GrooupBox groupBox2 = new GroupBox();
        groupBox2.add(vPanel2);


        listBoxE = new ListBox();
        listBoxF = new ListBox();

        VerticalPanel vPanel3 = new VerticalPanel();
        vPanel3.add(listBoxE);
        vPanel3.add(listBoxF);

        GrooupBox groupBox3 = new GroupBox();
        groupBox3.add(vPanel3);


        listBoxE = new ListBox();
        listBoxF = new ListBox();

        VerticalPanel vPanel4 = new VerticalPanel();
        vPanel4.add(ListBoxE);
        vPanel4.add(ListBoxF);
        ....

        GrooupBox groupBox3 = new GroupBox();
        groupBox3.add(vPanel4);



        listBoxG = new ListBox();
        listBoxH = new ListBox();
        ....

        VerticalPanel vPanel = new VerticalPanel();
        vPanel.add(ListBoxG);
        vPanel.add(ListBoxH);
        ....

        GrooupBox groupBox4 = new GroupBox();
        groupBox4.add(vPanel);

        ......
        //create Horizontal/vertical panels, docklayout panel as well, to position the group boxes on the gui
        ....

    }

    @Override
    void methodA(){
        //uses listBoxA
    }

    @Override
    void methodB(){
        //used listBoxB
    }

    @Override
    void methodC(){
        //uses listBoxC
    }

    @Override
    void methodD(){
        //uses listBoxD
    }

    @Override
    void methodE(){
        //uses listBoxE
    }

    @Override
    void methodF(){
        //uses listBoxF
    }

    @Override
    void methodG(){
        //uses listBoxG
    }

    @Override
    void methodH(){
        //uses listBoxH
    }   

    . 
    .
    .

    @Override
    void methodM(){
        //uses listBoxM
      } 


     }

I have tried as follows:

ContactPreseter.java

  public class ContactPresenter
{
    public interface Display extends groupBox1View.Display, groupBox2View.Display, groupBox3View.Display, groupBox4View.Display
    {

    }
}

preseter classes of each group box

public class groupBox1Presenter
{
    public interface Display
    {
        void methodA();
        void methodB();
    }
}

public class groupBox2Presenter
{
    public interface Display
    {
        void methodC();
        void methodD();
    }
}


public class groupBox3Presenter
{
    public interface Display
    {
        void methodE();
        void methodF();
    }
}


public class groupBox4Presenter 
{
    public interface Display
    {
        void methodG();
        void methodH();
    }
}

ContactView.java

    public abstract  class ContactView implements ContactPresenter.Display
{
    // adds group boxes to horizontal/vertical panels, and docklayout panel
}

Below are the view classes for each group box:

But here I eclipse forces me to implement all the methods of the interface ContactPresenter.Display in each of these classes whereas , I wanted it to be the way you see implemented here.

I was wondering if there were a way to play with access modifiers in order to achieve that ? If not, please I would you to help with ideas how to do it ?

public groupBox1View extends ContactView implements groupBox1Presenter
{
    public groupBox1View()
    {

    }

    @Override
    void methodA(){
        //uses listBoxA
    }

    @Override
    void methodB(){
        //used listBoxB
    }
}

public groupBox2View extends ContactView implements groupBox2Presenter
{
    public groupBox2View()
    {

    }

    @Override
    void methodC(){
        //uses listBoxC
    }

    @Override
    void methodD(){
        //used listBoxD
    }
}

public groupBox3View extends ContactView implements groupBox3Presenter
{
    public groupBox3View()
    {

    }

    @Override
    void methodE(){
        //uses listBoxE
    }

    @Override
    void methodF(){
        //used listBoxF
    }
}


public groupBox4View extends ContactView implements groupBox4Presenter
{
    public groupBox4View()
    {

    }

    @Override
    void methodG(){
        //uses listBoxG
    }

    @Override
    void methodH(){
        //used listBoxH
    }
}
Gerko Ford
  • 41
  • 2
  • 12

1 Answers1

0

You are right, your view is growing too big. You need to cut it into components which are handling their own concerns.

The editor framework will prove helpful but has it's own caveats.

In the end, you have one presenter, working with the whole thing, but only reading and writing one contact object.

You build your view from multiple components, each may have it's own presenter and is responsible for one part of your large contact object.

An example: Instead of running 10 listboxes of generic type, make that 10 semantically different components, responsible for selection of different types of data: AgeListBox, CityListBox, FooListBox, BarListBox. This will seperate the data provisioning for the boxes out of your central presenter, and into the specific presenters for each listbox.

Start at the lowest level and combine editing views for each semantic unit and combine them to larger return objects:

NameEditor, AgeEditor, FooEditor, BarEditor are combined into an AddressEditor, which assembles with a CVEditor into something bigger until you finally arrive at the contact level.

I hope this makes sense to you.

UPdate: You asked for code, let's try some pseudocode:

Let's say you have a profile you want to edit. It contains of

  • the user's personal data
    • contains the user address
    • a bunch of email or mobile addresses
    • an image or connection to Gravatar
    • payment information
  • the list of tags the user is interested in
  • the list of channels he subscribed
  • Newsletter/marketing information
public class UserProfile {
    PersonalData person;
    List<NewsTopic> topicsOfInterest;
    List<NewsChannel> subscriptions;
    MarketingInfo marketingInfo;

    // bean stuff, constr, equals etc.
}

public class PersonalData {
    String name;
    String firstName;
    List<ContactDevice>phoneAndMailList;
    ImageContainer userImage;
    BankAccount paymentData;
}

You get the idea, I guess...

You can now write ONE view class, detailing all the information you see here, resulting in a monolitic monster view and the matching monster presenter. Or you follow the advice in the gwtproject and cut the view in small as possible pieces (components). That is, subviews and presenters that form a hierarchy, matching the one of your UserProfile class. This is basically what the editor framework is really good at.

In the editor fw, the views are called "Editors" (makes sense), and they get fed the data from top editor down to the smallest part by an EditorDriver class. GWT will generate most of the code for you, which is very cool, but also is not working so perfect, if you have optional parts in the profile.

If we would implement this ourselves, you will build a structure like the following (I avoid the "Editor" and replaced by "Dialog"):

public class UserProfileDialogView extends Component implements HasValue<UserProfile> {
    // subviews 
    @UiField
    PersonalDataDialog personDataDlg;
    @UiField
    UserTopicListDialog topicListDlg;
    @UiField
    SubscriptionListDialog subscriptionListDlg;
    @UiField
    MarketingInfoDialog marketingInfoDlg;

    @Overwrite 
    public UserProfile getValue() {
       // we do not need to copy back the data from the sub-dialogs, because we gave them the values from the profile itself. 
       // Beware, substructures cannot be null in such a case!
       return userProfile;
    }

    @Ovewrite
    public void setValue(UserProfile profile) {
        this.userProfile = profile;
        // option one: manually distribute the profile parts
        personDataDlg.getPresenter().setValue(profile.getPerson());
        topicListDlg.getPresenter().setValue(profile.getTopicsOfInterest());
        subscriptionListDlg.getPresenter().setValue(profile.getSubscriptions());
        // option two: use eventbus and valuechanged event, dialogs are 
    }
}

There is now a variance of concerns: Who will set the value in the sub-dialogs. You can forward to the presenter of the sub-dialog, or you set it directly in the sub-dialog.

Anyway, what should get clear to you now, is that you do not have only one presenter to rule all parts of the view. You need to split the presenters to be responsible for one subview each. What I found useful in such a large dialog tree, was to have a separate model class, that keeps the object currently beeing edited and provides change communication logic for other dialogs. For example, if you add a list of topics, and you add one topic, the dialog for the channel subscription selection may want to know, that there is now one more topic to be shown in the topic-filter.

thst
  • 4,592
  • 1
  • 26
  • 40
  • Thanks Thst for your answer. I am not sure I understand well what you mean. Could you please write a example code to help me understand it better ? I would really appreciate that :) – Gerko Ford Oct 10 '16 at 06:50