chandil03 chandil03 - 4 months ago 28
Android Question

Why to make an interface in Presenter if we can just return a value and set in a View (MVP Structure)

It has been two months, i have been working with MVP Structure for creating Android apps.

As explained in every link i found regarding MVP that Presenter class takes care of all business login and data(from Model class), I understood that and started working.

One of the advantages shown in tutorials, i want to emphasise it here that MVP make unit testing easier because there is no dependency of views(Fine i understood that also).

What i did not understand is why to make interface to update views from presenter whereas i can just call a method of presenter that will return a value and i can set it there?

Lets come to the advantage i talked about above(Unit testing). Using those interface unit testing will be more problematic as method will require an interface implementation to complete an operation that we do not have in Unit testing(I know Instrumental test also comes in unit test but i m talking about only non-ui testing).

I just prefer to call a presenter method and get value and set in view in fragment or activity itself where as creation of interface creates another level of complexity and unnecessary interface declaration there all view operations are to be implemented. Its kind of frustrating.

One of the friend i am working with pointed out this problem in my code and told me to look all online references to clarify my mistake. But i want to know how these interfaces is help full in programming practice. Because i can not just digest it. Its becoming a pain in my ass. I have looked all the online references no solution.

Example



Presenter with interface

class Presenter
{

private ViewInterface viewInterface;

public void setViewInterface(ViewInterface viewInterface)
{
this.viewInterface = viewInterface;
}

// Here value is being passed to interface method that is implemented in fragment.
// No problem with this implementation but why to do it.
// It will make unit test problematic as this method needs ViewInterface.
public void calculate()
{
// Some calculation
viewInterface.updateView(/*pass some paramerer*/);
}
}


Presenter without interface

class Presenter
{


// Here just take the value and set the view in fragment
// Unit test easier just check the returned value.
public int calculate()
{
int result = -1;
// Some calculation
return result;
}
}


Fragment where presenter is being used

class MyFragment extends Fragment{

....

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.layout1, container, false);
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
// just call method and get value to set in a view.
int result = new Presenter().calculate();
// set result in a view
}

}


Please check comments in above code.

Any help will be appreciated.
Thanks in advance.

Answer

Why the view should be implemented with an interface in this pattern?

Because we want to decouple the code from the implementation view. We want to abstract the framework used to write our presentation layer, regardless of any external dependency. We want to be able to easily change the implementation view if needed. We want to follow the dependency rule to improve unit testability. Please bear on mind that in order to follow the dependency rule, high level concepts -such as the presenter implementation, can't depend on low level details like the implementation view.

Why the interface is needed to improve unit testability?

Because to write a unit test, the entire code should be related to your domain as opposed to external systems such as a SDK or a framework.

Let's illustrate this with a case scenario related to a login screen implemented for Android, Please don't pay attention to the code syntax, it's almost pseudocode:

/**
* Login use case. Given an email and password executes the login process.
*/
public class Login {

private LoginService loginService;

public Login(LoginService loginService) {
    this.loginService = loginService;
}

public void performLogin(String email, String password, LoginCallback callback) {
  boolean loginSuccess = loginService.performLogin(email, password);
  if (loginSuccess) {
    callback.onLoginSuccess();
  } else {
    callback.onLoginError();
  }
}
}

/**
* LoginPresenter, where the presentation logic related to the login user interface is implemented.
*/
public class LoginPresenter {

private LoginView view;
private Login login;

public LoginPresenter(LoginView view, Login login) {
    this.view = view;
    this.login = login;
}

public void onLoginButtonPressed(String email, String password) {
    if (!areUserCredentialsValid(email, password)) {
        view.showInvalidCredentialsMessage();
        return;
    }

    login.performLogin(email, password, new LoginCallback {
        void onLoginSuccess() {
            view.showLoginSuccessMessage();
        }

        void onLoginError() {
            view.showNetworkErrorMessage();
        }
    });
}

}

/**
* Declares what the presenter can do with the view without generating coupling to the view implementation details.
*/
public interface LoginView {

  void showLoginSuccessMessage()
  void showInvalidCredentialsMessage()
  void showNetworkErrorMessage()

}

public class LoginActivity extends Activity implements LoginView {

.........

}

Why the interface view is needed here?

It is needed to be able to write an unit test replacing the implementation view with a test double. Why is this needed in the unit test context? Because you don't want to mock the Android SDK and use the LoginActivity inside your unit tests. Remember that any test where the Android SDK is part of the SUT is not a unit test.

For more info visit this blog where i think you will get the answer.

Comments