zoukankan      html  css  js  c++  java
  • MVP模式入门案例

    随着UI创建技术的功能日益增强,UI层也履行着越来越多的职责。为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数据的可视化以及与用户的交互,同时让Model只关系数据的处理,基于MVC概念的MVP(Model-View-Presenter)模式应运而生。


    四个要素:
    (1)View:负责绘制UI元素、与用户进行交互(在Android中体现为Activity);
    (2)View interface:需要View实现的接口,View通过View interface与Presenter进行交互,降低耦合,方便进行单元测试;
    (3)Model:负责存储、检索、操纵数据(有时也实现一个Model interface用来降低耦合);
    (4)Presenter:作为View与Model交互的中间纽带,处理与用户交互的负责逻辑。

    为什么使用MVP模式

    在Android开发中,Activity并不是一个标准的MVC模式中的Controller,它的首要职责是加载应用的布局和初始化用户界面,并接受并处理来自用户的操作请求,进而作出响应。随着界面及其逻辑的复杂度不断提升,Activity类的职责不断增加,以致变得庞大臃肿。当我们将其中复杂的逻辑处理移至另外的一个类(Presneter)中时,Activity其实就是MVP模式中View,它负责UI元素的初始化,建立UI元素与Presenter的关联(Listener之类),同时自己也会处理一些简单的逻辑(复杂的逻辑交由Presenter处理).
    另外,回想一下你在开发Android应用时是如何对代码逻辑进行单元测试的?是否每次都要将应用部署到Android模拟器或真机上,然后通过模拟用户操作进行测试?然而由于Android平台的特性,每次部署都耗费了大量的时间,这直接导致开发效率的降低。而在MVP模式中,处理复杂逻辑的Presenter是通过interface与View(Activity)进行交互的,这说明了什么?说明我们可以通过自定义类实现这个interface来模拟Activity的行为对Presenter进行单元测试,省去了大量的部署及测试的时间。

     


    MVP与MVC的异同

    MVC模式与MVP模式都作为用来分离UI层与业务层的一种开发模式被应用了很多年。在我们选择一种开发模式时,首先需要了解一下这种模式的利弊:

    无论MVC或是MVP模式都不可避免地存在一个弊端:额外的代码复杂度及学习成本。
    这就导致了这两种开发模式也许并不是很小型应用。

    但比起他们的优点,这点弊端基本可以忽略了:
    (1)降低耦合度
    (2)模块职责划分明显
    (3)利于测试驱动开发
    (4)代码复用
    (5)隐藏数据
    (6)代码灵活性

    登录Demo案例演示

    步骤

    1. 首先完成User Been文件的创建,在这里面,我们只需要要User的serget方法。
    2. 接着思考User有什么业务,并将这些业务统统添加进入IUserBiz接口中。
    3. 每一个业务逻辑都有一个附带的Listener,这个Listener中有执行这个业务后会发生的事情。
    4. 然后UserBiz 将 IUserBiz中的功能实现。
    5. 对应的View(Activity)中的功能写一个 接口出来。
    6. 对应的View(Activity)实现接口。
    7. 实现Presenter,Presenter的作用就是将View与Model进行连接。

    步骤一 User Been的创建

    仔细看我上面那个登录界面,然后回答:

    • 根据上面的图片如果是你创建一个User,里面有什么属性?

    然后你想象我们有登录与清除的功能,那你的User中需要有什么方法?

    •	public class User {
        private String username ;
        private String password ;
    
        public String getUsername()
        {
            return username;
        }
    
        public void setUsername(String username)
        {
            this.username = username;
        }
    
        public String getPassword()
        {
            return password;
        }
    
        public void setPassword(String password)
        {
            this.password = password;
        }
    

    步骤二 IUserBiz接口的创建

    思考:我们已经有一个User Been了,我们需要用这个User进行什么操作?并将User即将进行的操作写为抽象方法。

    public interface IUserBiz {
        public void login(String username, String password, OnLoginListener loginListener);
    }
    

    步骤三 附带的Listener创建

    思考:我们之前创建的IUserBiz接口中的方法有哪种情况会发生?并将可能会出现的情况进行写入抽象Listener中去。

    public interface OnLoginListener {
        void loginSuccess(User user);
        void loginFailed();
    }
    

    步骤四 创建UserBiz直接实现IUserBiz

    就是将方法实现

    public class UserBiz implements IUserBiz {
        @Override
        public void login(final String username, final String password, final OnLoginListener loginListener) {
            //模拟子线程耗时操作
            new Thread() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //模拟登录成功
                    if ("123".equals(username) && "123".equals(password)) {
                        User user = new User();
                        user.setUsername(username);
                        user.setPassword(password);
                        loginListener.loginSuccess(user);
                    } else {
                        loginListener.loginFailed();
                    }
                }
            }.start();
        }
    }
    

    步骤六 将View(Activity)连接创建好的接口并实现

    根据接口并实现

    public class UserLoginActivity extends ActionBarActivity implements IUserLoginView {
        private EditText mEtUsername, mEtPassword;
        private Button mBtnLogin, mBtnClear;
        private ProgressBar mPbLoading;
    
        private UserLoginPresenter mUserLoginPresenter = new UserLoginPresenter(this);
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_user_login);
    
            initViews();
        }
    
        private void initViews() {
            mEtUsername = (EditText) findViewById(R.id.id_et_username);
            mEtPassword = (EditText) findViewById(R.id.id_et_password);
    
            mBtnClear = (Button) findViewById(R.id.id_btn_clear);
            mBtnLogin = (Button) findViewById(R.id.id_btn_login);
    
            mPbLoading = (ProgressBar) findViewById(R.id.id_pb_loading);
    
            mBtnLogin.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mUserLoginPresenter.login();
                }
            });
    
            mBtnClear.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mUserLoginPresenter.clear();
                }
            });
        }
    
    
        @Override
        public String getUserName() {
            return mEtUsername.getText().toString();
        }
    
        @Override
        public String getPassword() {
            return mEtPassword.getText().toString();
        }
    
        @Override
        public void clearUserName() {
            mEtUsername.setText("");
        }
    
        @Override
        public void clearPassword() {
            mEtPassword.setText("");
        }
    
        @Override
        public void showLoading() {
            mPbLoading.setVisibility(View.VISIBLE);
        }
    
        @Override
        public void hideLoading() {
            mPbLoading.setVisibility(View.GONE);
        }
    
        @Override
        public void toMainActivity(User user) {
            Toast.makeText(this, user.getUsername() +
                    " login success , to MainActivity", Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void showFailedError() {
            Toast.makeText(this,
                    "login failed", Toast.LENGTH_SHORT).show();
       
    

    步骤七 实现Presenter

    在MVP中Presenter将Model与View进行一个连接,在这个地方的Presenter属于一个中间人的传话的效果。
    那么在这个Presenter类中,主要就是图中Button的方法,也就是一个login方法,一个clear方法,具体实现还是将之前所实现的接口进行一个方法对接。

    //将**View**与**Model**之间进行操作。
    public class UserLoginPresenter {
        private IUserBiz       userBiz;
        private IUserLoginView userLoginView;
        private Handler mHandler = new Handler();
        ////传递一个loginView
        public UserLoginPresenter(IUserLoginView userLoginView) {
            
            //这个是View的代表
            this.userLoginView = userLoginView;
            //这个是Model的代表
            this.userBiz = new UserBiz();
        }
        //下面有两个方法主要是将两个**Button**的操作直接封装完成,然后直接使用
        public void login() {
            userLoginView.showLoading();
            userBiz.login(userLoginView.getUserName(), userLoginView.getPassword(), new OnLoginListener() {
                @Override
                public void loginSuccess(final User user) {
                    //需要在UI线程执行
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            userLoginView.toMainActivity(user);
                            userLoginView.hideLoading();
                        }
                    });
    
                }
    
                @Override
                public void loginFailed() {
                    //需要在UI线程执行
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            userLoginView.showFailedError();
                            userLoginView.hideLoading();
                        }
                    });
    
                }
            });
        }
        // //这个是clear按钮
        public void clear() {
            userLoginView.clearUserName();
            userLoginView.clearPassword();
        }
    
    }
    

    解答

    一 User Been的创建

    仔细看我上面那个登录界面,然后回答:

    • 根据上面的图片如果是你创建一个User,里面有什么属性?
    • 然后你想象我们有登录与清除的功能,那你的User中需要有什么方法?
    回答:
    1.User有userName与password两个属性。
    2.userName与password拥有setget方法即可。

    二 IUserBiz接口的创建

    思考:我们已经有一个User Been了,我们需要用这个User进行什么操作?
    并将User即将进行的操作写为抽象方法。

    回答:
    User需要有一个login的功能,这个功能中我们需要将我们的账号密码传递进
    去,同时还有一个Listener需要监听login的情况,在下面就是Listener的创
    建了。

    三 附带的Listener创建

    思考:我们之前创建的IUserBiz接口中的方法有哪种情况会发生?
    并将可能会出现的情况进行写入抽象Listener中去。

    回答:
    以前接口中主要实现了一个login的功能,这个功能会有两种可能发生,第一
    种就是登录成功,第二种就是登录失败。

    四 创建UserBiz直接实现IUserBiz

    就是将方法实现。

    五 将View(Activity)中的功能写入接口

    仔细看我上面那个登录界面,然后回答:

    • Activity中有两个Button,点击一下会进行什么操作?
    • 操作过程中会发生什么情况,并将情况转换成对应的方法。
      回答:
      1.点击login会有登录成功或者登录失败,在这里登录需要获取Edit的信息。
      2.点击clear会清除EditView。
      那么方法如下:
      登录成功方法
      登录失败方法
      获取UserName
      获取PassWord
      清除Edit框

    六 将View(Activity)连接创建好的接口并实现

    根据接口并实现。

    七 实现Presenter

    在MVP中Presenter将Model与View进行一个连接,在这个地方的Presenter属于一个中间人的传话的效果。
    那么在这个Presenter类中,主要就是图中Button的方法,也就是一个login方法,一个clear方法,具体实现还是将之前所实现的接口进行一个方法对接。

     

     
     
  • 相关阅读:
    Callback2.0
    设计模式之Composite
    设计模式之Proxy
    React Native DEMO for Android
    React Native 与 夜神模拟器的绑定
    Skipping 'Android SDK Tools, revision 24.0.2'; it depends on 'Android SDK Platform-tools, revision 20' which was not installed.
    .ui/qrc文件自动生成.py文件
    简单排序算法
    Big O
    设计模式之Adapter
  • 原文地址:https://www.cnblogs.com/loaderman/p/6440554.html
Copyright © 2011-2022 走看看