MVP架构

本文介绍了MVP架构,详细解释了MVP的组成部分:View、View Interface、Model和Presenter,并探讨了使用MVP的原因,如降低耦合度、便于测试。同时,文章提供了MVP实例代码,并总结了MVP的优点和缺点,强调了其在Android开发中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MVP架构

一、什么是MVP和MVP结构?

  • MVP是由MVC演变而来的,然而MVP是Model, View和Presenter的简称。Model提供数据(Model并不 是必须
    有的,但是一定会有View和Presenter),View负责显示,Presenter负责逻辑的处理。在MVP中View并不
    直接使用Model,它们之间的通信是通过Presenter ,所有的交互都发生在Presenter内部。
    这里写图片描述
  • 在MVP模式里通常包含4个要素:

    1、View: 负责绘制UI元素、与用户进行交互(在Android中体现为Activity);

    2、View interface: 需要View实现的接口,View通过View interface与Presenter进行交互,降低耦合,方便进行单元测试;

    3、Model: 数据处理和业务逻辑部分(有时也实现一个Model interface用来降低耦合);

    4、Presenter: 作为View与Model交互的中间纽带,处理与用户交互的负责逻辑。

二、为什么要用MVP。

  • 因为在Android中,Activity严重耦合了界面和数据获取层。这样不仅导致了Activity的类越来越庞大,
    而且,如果修改数据获取层,可能也导致整个View 都要重写。也非常不利于模块和自动化测试。MVP使
    View独立于数据,把大量的 逻辑从Activity中提取出来。把应用分层,每层都可以独立测试和变动。

三、MVP的实例代码。

  • IView接口类 InterfaceSummaryView.java

/**
 * View接口读取数据
 * Created by Administrator on 2016/3/24.
 */
public interface InterfaceSummaryView {

    void showData(VehicleModel vehicleModel); //显示数据

    void concealProgressBar();//关闭进度条

    void showSeparator();//显示分割线

    void setData(VehicleModel vehicleModel);//给对象赋值

    void ErrorPrompt(String message); //没有数据时候的提示语

    String getSearchValue(); //获得关键字

    String getVehicleId(); //获得车型ID

    Boolean getFlag();//是否从搜索界面进来的

    void NextToActivity(); //跳转到下一个界面

}
  • 展示界面 VehicleSummaryActivity.java
 /**
 * 展示界面
 * Created by Administrator on 2016/1/5.
 */
public class VehicleSummaryActivity extends BaseActivity implements View.OnClickListener,
        InterfaceSummaryView {
              @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.vehicle_summary);

        initVehicleView();
        presenter.loadData();

    }

    //初始化控件
    private void initVehicleView() {
        presenter = new PresenterVehicleSummary(this, this);

        ......

    }

    @Override
    public String getSearchValue() {return getIntent().getExtras().getString(SEARCH_KEY); }

    @Override
    public String getVehicleId() {return getIntent().getExtras().getString(VEHICLE_ID);}

    @Override
    public Boolean getFlag() { return getIntent().getExtras().getBoolean(IS_SEARCH);}

    /**
     * 给控件赋值
     */
    @Override
    public void showData(VehicleModel vehiclemodel) {...... }

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

    @Override
    public void showSeparator() {  separator.setVisibility(View.VISIBLE);  }

    @Override
    public void setData(VehicleModel model) {  vehicleModel = model; }


    @Override

    public void ErrorPrompt(String message) {
            Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void NextToActivity() {
            new ActivityUtil().startMainActivity(this, vehicleModel.getModelName(), vehicleModel.getModelId());

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.back:
                finish();
                break;
            case R.id.ll_part:
                presenter.ToNextActivity();
                break;
        }
    }


  }
  • Presenter类 PresenterVehicleSummary.java
/**
 * Presenter类处理数据和刷新界面
 * Created by Administrator on 2016/3/24.
 */
public class PresenterVehicleSummary {

    private InterfaceSummaryView infoView;

    private Activity mActivity;

    private VehicleModel vehicleModel;

    public PresenterVehicleSummary(Activity mActivity, InterfaceSummaryView infoView) {

        this.mActivity = mActivity;

        this.infoView = infoView;

    }

    /**

     * 加载数据

     */

   public void loadData() {

        String url = "";

        if (infoView.getFlag()) {

            if (!StringUtils.isEmpty(infoView.getSearchValue()))

                //根据关键字来查询的URL

                url = ServiceEndPoint.GetSearchUri(SearchTypeEnum.SearchType.VIN.getType(), infoView.getSearchValue(), 0, 10);

        } else {

            if (!StringUtils.isEmpty(infoView.getVehicleId()))

                //根据车型ID来查询的URL

                url = ServiceEndPoint.GetVehicleModelsParticularsUri(infoView.getVehicleId());

        }

        JsonObjectRequest request = VolleyHelper.newJsonObjectRequest(url, null, new Response.Listener<JSONObject>() {

            @Override

            public void onResponse(JSONObject jsonObject) {

                try {

                    infoView.concealProgressBar();

                    infoView.showSeparator();

                    if (infoView.getFlag()) {

                        if (jsonObject.toString().equals("{}"))

                            infoView.ErrorPrompt("没有查到该车的相关数据");

                        vehicleModel = GsonHelper.newGson().fromJson(jsonObject.get("result").toString(), VehicleModel.class);

                    } else {

                        vehicleModel = GsonHelper.newGson().fromJson(jsonObject.toString(), VehicleModel.class);

                    }

                    if (vehicleModel == null) {

                          infoView.ErrorPrompt("没有查到该车的相关数据");

                    } else {

                        infoView.showData(vehicleModel);

                        infoView.setData(vehicleModel);

                    }

                } catch (JSONException e) {

                    e.printStackTrace();

                }

            }

        }, new GenericErrorListener(mActivity) {

            @Override

            public void onErrorResponse(VolleyError error) {

                super.onErrorResponse(error);

            }

        }, getAccessToken());

        VolleySingleton.getInstance(mActivity).addToRequestQueue(request);

    /**

     * 跳转到下个页面

     */

    public void ToNextActivity() {

        if (vehicleModel == null) {

            infoView.ErrorPrompt("暂无数据不能查看全车件");

        } else {

            infoView.NextToActivity();

        }

    }

    public String getAccessToken() {

        User user = User.getInstance(mActivity);

        if (user == null)

            return null;

        return user.getAccessToken();

    }

}

四、总结

  • MVP的优点

    1、降低耦合度,模型与视图完全分离,可以修改视图而不影响模型。

    2、可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部。

    3、可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁。

    4、如果把逻辑放在Presenter中,那么就可以脱离用户接口来测试这些逻辑(单元测试)。

  • MVP的缺点

    1、 Presenter中除了应用逻辑以外,还有大量的View->Model,Model->View的手动同步逻辑,造成Presenter比较笨重,维护起来会比较困难。

    2、 由于对视图的渲染放在了Presenter中,所以视图和Presenter的交互会过于频繁。

    3、 如果Presenter过多地渲染了视图,往往会使得它与特定的视图的联系过于紧密。一旦视图需要变更,那么Presenter也需要变更了。

    Android官方MVP架构示例

### MVP 架构概述 MVP(Model-View-Presenter)是一种常见的软件设计模式,主要用于分离关注点并提高应用程序的可维护性和可测试性。它通过将界面逻辑与业务逻辑解耦,使得开发者可以更轻松地管理复杂的应用程序结构。 #### 应用场景 MVP 软件架构能够适应多种应用场景,在实际项目中可以帮助开发团队构建更加模块化、清晰化的代码体系[^1]。无论是小型工具还是大型企业级应用,都可以从中受益。 --- ### MVP 的核心组件及其职责 MVP 主要由三个部分组成: 1. **Model**: 表示数据层,负责处理所有的数据操作,比如数据库交互或者网络请求。 2. **View**: 表示用户界面层,主要展示数据给用户,并接收用户的输入事件。 3. **Presenter**: 是连接 Model 和 View 的桥梁,承担着大部分的业务逻辑和控制流的任务。 这种分层的设计让每一块的功能都变得单一而专注,从而提升了整体系统的灵活性和扩展能力。 --- ### 实现方式:以登录功能为例 为了更好地理解如何实现 MVP 模式,可以通过一个具体的例子——即简单的登录页面来说明其工作流程[^2]。 以下是基于 Java 编写的简单 MVP 登录功能的代码片段: #### 1. 定义接口 `LoginContract` ```java public interface LoginContract { interface Presenter { void login(String username, String password); } interface View { void showLoading(); void hideLoading(); void showError(String message); void navigateToHome(); } } ``` #### 2. 创建模型类 `LoginModel` ```java public class LoginModel { public boolean validateCredentials(String username, String password) { // 假设验证逻辑在此处完成 return "admin".equals(username) && "password".equals(password); } } ``` #### 3. 设计视图类 `LoginActivity` (作为 View) ```java public class LoginActivity extends AppCompatActivity implements LoginContract.View { private EditText etUsername; private EditText etPassword; private Button btnLogin; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); etUsername = findViewById(R.id.et_username); etPassword = findViewById(R.id.et_password); btnLogin = findViewById(R.id.btn_login); btnLogin.setOnClickListener(v -> presenter.login(etUsername.getText().toString(), etPassword.getText().toString())); } private LoginContract.Presenter presenter = new LoginPresenter(this); @Override public void showLoading() { /* 显示加载动画 */ } @Override public void hideLoading() { /* 隐藏加载动画 */ } @Override public void showError(String message) { /* 展示错误提示 */ } @Override public void navigateToHome() { /* 导航到主页 */ } } ``` #### 4. 开发 Presenter 类 `LoginPresenter` ```java public class LoginPresenter implements LoginContract.Presenter { private final LoginContract.View view; private final LoginModel model; public LoginPresenter(LoginContract.View view) { this.view = view; this.model = new LoginModel(); } @Override public void login(String username, String password) { if (username.isEmpty() || password.isEmpty()) { view.showError("请输入完整的用户名和密码!"); return; } view.showLoading(); if (model.validateCredentials(username, password)) { view.navigateToHome(); } else { view.showError("用户名或密码不正确!"); } view.hideLoading(); } } ``` 上述代码展示了 MVP 中各角色之间的协作关系,其中 Presenter 承担了绝大部分的工作量,包括校验输入、调用 Model 方法以及更新 UI 状态等任务。 --- ### MVP 的优缺点分析 尽管 MVP 提供了许多优势,但也存在一些局限性需要考虑: - **优点**: - 清晰划分责任边界,便于单元测试。 - 减少对具体框架的依赖程度,提升跨平台移植的可能性。 - **缺点**: - 可能导致代码冗余度增加,尤其是当项目规模较大时,过多的接口定义会让代码难以阅读和维护[^3]。 - 如果未合理规划,则容易使 Presenter 成为臃肿的核心部件,反而降低了后续修改效率[^4]。 综上所述,虽然 MVP 不是完美的解决方案,但在许多情况下仍然是值得推荐的选择之一。 --- ### 总结 通过对 MVP 结构的学习可知,该方法论不仅有助于改善传统单体架构下的混乱局面,而且还能促进团队成员之间高效沟通合作。然而需要注意的是,在采用此方案前应充分评估潜在风险因素,以便扬长避短发挥最大效能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值