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.
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
}
}
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
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
UserProfileclass. 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
EditorDriverclass. 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"):
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.