🧑‍💻逍遥猫工社🤖

MVP(Model-View-Presenter)是MVC(Model-View-Controller)架构的一种演进模式,主要用于改善MVC在UI交互和测试方面的局限性。它在桌面应用(如Java Swing、.NET WinForms)和Android开发中广泛应用,后来也被一些Web框架(如GWT)采用。


1. MVP 核心组件#

组件职责
Model负责数据逻辑(如数据库、网络请求、业务规则),与MVC中的Model类似。
View负责UI展示(如Activity、Fragment、Web页面),但不处理业务逻辑
Presenter作为View和Model的中间人,处理用户交互,更新Model并通知View刷新。

2. MVP 工作原理#

  1. 用户操作View(如点击按钮)。
  2. View将事件转发给Presenter(不直接处理逻辑)。
  3. Presenter调用Model获取或更新数据。
  4. Model返回结果给Presenter
  5. Presenter更新View(如显示数据、错误提示)。

关键特点

  • View是被动的:仅负责渲染UI,不直接与Model交互。
  • Presenter是主动的:控制流程,决定何时更新View和Model。
  • Model独立:与View无直接依赖,便于测试和复用。

3. MVP 的优势#

(1) 更清晰的职责分离#

  • View只负责显示,Presenter处理逻辑,避免MVC中Controller和View的模糊边界。
  • 适合复杂UI交互(如表单验证、多步骤流程)。

(2) 更高的可测试性#

  • Presenter不依赖Android API或DOM,可直接用JUnit测试。
  • View可通过Mock对象测试,无需真实UI环境。

(3) 降低耦合#

  • View通过接口(如IView)与Presenter通信,便于替换UI框架(如从Android转向Flutter)。
  • Model可独立修改,不影响View。

(4) 解决MVC的“胖Controller”问题#

  • MVC的Controller可能混杂业务逻辑和UI逻辑,而MVP的Presenter更专注于流程控制。

4. MVP 的缺点#

(1) 代码量增加#

  • 需要定义View接口(如ILoginView)和Presenter,对小项目可能显得冗余。

(2) Presenter可能变“胖”#

  • 复杂页面可能导致Presenter逻辑膨胀,需进一步拆分(如按功能模块分多个Presenter)。

(3) 手动绑定较繁琐#

  • 需要显式编写View和Presenter的绑定代码(现代框架如MVVM通过数据绑定自动化)。

5. MVP vs. MVC vs. MVVM#

特性MVCMVPMVVM
View职责可能包含逻辑完全被动完全被动
数据绑定无(或手动)手动(Presenter更新View)自动(双向绑定)
测试难度较高(依赖UI)低(Presenter可独立测试)低(ViewModel可测试)
典型框架Spring MVC、Ruby on RailsAndroid、GWTVue.js、WPF、Jetpack Compose

6. MVP 代码示例(Android)#

(1) 定义View接口#

public interface ILoginView {
    void showLoading();
    void hideLoading();
    void onLoginSuccess(String message);
    void onLoginError(String error);
}
java

(2) Presenter 实现#

public class LoginPresenter {
    private ILoginView view;
    private UserModel model;

    public LoginPresenter(ILoginView view) {
        this.view = view;
        this.model = new UserModel();
    }

    public void login(String username, String password) {
        view.showLoading();
        model.login(username, password, new Callback() {
            @Override
            public void onSuccess() {
                view.hideLoading();
                view.onLoginSuccess("登录成功!");
            }

            @Override
            public void onFailure(String error) {
                view.hideLoading();
                view.onLoginError(error);
            }
        });
    }
}
java

(3) View(Activity)实现#

public class LoginActivity extends AppCompatActivity implements ILoginView {
    private LoginPresenter presenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        presenter = new LoginPresenter(this);

        Button btnLogin = findViewById(R.id.btn_login);
        btnLogin.setOnClickListener(v -> {
            String username = editUsername.getText().toString();
            String password = editPassword.getText().toString();
            presenter.login(username, password);
        });
    }

    @Override
    public void showLoading() {
        progressBar.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideLoading() {
        progressBar.setVisibility(View.GONE);
    }

    // 其他接口方法...
}
java

7. 适用场景#

  • Android开发:Activity/Fragment作为View,Presenter处理业务逻辑。
  • 桌面应用:如Java Swing、.NET WinForms。
  • 需要高测试性的项目:单元测试覆盖Presenter逻辑。

总结#

MVP通过被动View主动Presenter解决了MVC的部分问题,尤其适合UI逻辑复杂的场景。但随着现代框架(如MVVM、Flux)的兴起,MVP在部分领域已被替代,但在Android传统开发中仍有一席之地。