5
\$\begingroup\$

My application uses a simple Model-View-Presenter architecture and uses the following classes and interface:

Presenter:

public abstract class Presenter<V> {

    private V view;

    public final void setView(V view) {
        this.view = view;
    }

    protected final V getView() {
        return this.view;
    }
}

View

public abstract class View<V, P extends Presenter<V>> implements ViewAdapter<V> {

    private final P presenter;

    public View(P presenter) {
        this.presenter = presenter;
    }

    protected final P getPresenter() {
        return this.presenter;
    }

    void initialize() {
        this.getPresenter().setView(this.asView());
    }
}

ViewAdapter

interface ViewAdapter<T> {
    T asView();
}

The application is then wired up like this:

  • A concrete Presenter is created.
  • A concrete View is created, passing in the concrete Presenter as a constructor parameter.
  • The View is initialised. During initialisation, the View calls the asView method to pass a view instance to the presenter.

Each concrete presenter in the application is parameterised with a view interface. Each concrete view class implements a view interface and can then pass itself to the presenter during initialisation and it is in this area that I am looking for advice.

The ViewAdapter interface exists solely to allow the concrete view to pass itself to the presenter via the asView method whilst maintaining type safety. My concrete views which derive from the View class are then forced to provide an implementation of the asView method in order to provide a view instance to the presenter that is of the correct type.

Every implementation looks the same:

@Override
public FooView asView() {
    return this; // this implements the FooView interface.
}

All this basically does is force 'this' to implement FooView as I am unable to express something like this:

// Example, not valid code, won't compile!
public abstract class View<V, P extends Presenter<V>> implements V {
}

Which would allow me to remove the ViewAdapter interface and pass the view to the presenter in the abstract View class like this, removing the redundancy:

void initialize() {
    this.getPresenter().setView(this);
}
\$\endgroup\$
  • \$\begingroup\$ I'm sure it's possible. We're not here to write code for you. We're just here to review your already existing code. \$\endgroup\$ – Simon Forsberg Jan 16 '14 at 19:15
  • 1
    \$\begingroup\$ 1). this is actual code from an application I am writing. I have just stripped out the noise to demonstrate the actual problem. 2). I haven't asked anyone to write this for me. I am asking for guidance on factoring out the redundancy introduced with the ViewAdapter interface. \$\endgroup\$ – Benjamin Jan 16 '14 at 19:23
  • \$\begingroup\$ I apologize. I'm stupid! Retracted close vote. \$\endgroup\$ – Simon Forsberg Jan 16 '14 at 19:35
  • 1
    \$\begingroup\$ try to use java generics constraints as Presenter<V extends View> \$\endgroup\$ – Bruno Costa Jan 16 '14 at 21:23
1
\$\begingroup\$

I tried it in an IDE and have some addition to the last comment. I agree that you should try

Presenter<V extends View>

plus I would add that you need to switch the signature to

public abstract class View<V, P extends Presenter> 

from

public abstract class View<V, P extends Presenter<V>>

That is regarding to make it compile. Additionally, you can discard generics V since it is not used anymore in the View so the final signature would be:

public abstract class View<P extends Presenter>

Then you can get rid of ViewAdapter and the initialize method should work as you want it:

void initialize() {
    this.getPresenter().setView(this);
}
\$\endgroup\$
0
\$\begingroup\$

After reviewing this code a few times I've come to the conclusion that there is no way to express what I am trying to say in Java I.E the View class must implement an interface of type V as in the (illegal) snippet below.

public abstract class View<V, P extends Presenter<V>> implements V {
}

This leaves me with the following options:

  1. Leave my code as is and accept the (minimal) redundancy.
  2. Remove some of the generic parameters and accept that if I configure my application incorrectly I will get an invalid cast exception.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.