美文网首页
设计模式与架构04 -- MVP架构

设计模式与架构04 -- MVP架构

作者: YanZi_33 | 来源:发表于2022-03-03 17:01 被阅读0次

    MVC架构

    • 在Android中MVC分别表示的含义如下:
      • M:表示单纯的Bean(Java Bean)数据模型;
      • V:表示View及其子类;
      • C:表示Activity和Fragment及其子类;
    • 在iOS中MVC分别表示的含义如下:
      • M:表示数据模型;
      • V:表示UIView控件;
      • C:表示控制器Controller;

    MVP

    • M:表示数据层,包括数据模型,数据库,文件操作,网络请求等等;
    • V:表示View,Acticity以及Fragment及其子类;
    • P:表示中介Presenter,是View层与Model层中间人;
    • MVP架构设计的目的是:将View层和Model数据层进行解耦分离;
    MVC项目 -- 登录
    • 下面以MVC架构 实现Android一个简单的登录逻辑,代码如下:
    • Model层:用户模型类User,单纯的数据模型;
    public class User {
        private String name;
        private int age;
    
        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    }
    
    • Controller层:MainActivity,代码如下:
    public class MainActivity extends AppCompatActivity {
    
        private EditText userNameEt;
        private EditText passworEt;
        private ProgressDialog progressDialog;
    
        private Callback callback;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            userNameEt = findViewById(R.id.user_name);
            passworEt = findViewById(R.id.password);
    
            progressDialog = new ProgressDialog(this);
            progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
            progressDialog.setCancelable(false);
            progressDialog.setMessage("请稍后...");
    
            callback = new Callback() {
                @Override
                public void onSuccess(User user) {
                    progressDialog.dismiss();
                    System.out.println("网络请求成功");
                    Toast.makeText(MainActivity.this,"成功!!!",Toast.LENGTH_SHORT).show();
                }
    
                @Override
                public void onFailure(String message) {
                    System.out.println(message);
                    Toast.makeText(MainActivity.this,"失败!!!",Toast.LENGTH_SHORT).show();
                }
            };
        }
    
        ///按钮的点击事件
        public void login(View view) {
            Log.e("MainActivity","登录");
            String user_name = userNameEt.getText().toString();
            String password = passworEt.getText().toString();
    
            if (user_name.isEmpty()) {
                Toast.makeText(MainActivity.this,"请输入用户名",Toast.LENGTH_SHORT).show();
                return;
            }
            if (password.isEmpty()) {
                Toast.makeText(MainActivity.this,"请输入密码",Toast.LENGTH_SHORT).show();
                return;
            }
    
            progressDialog.show();
            //模拟登录网络请求
            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                @Override
                public void run() {
                    User user = new User("yanzi",30);
                    callback.onSuccess(user);
                }
            },3000);
        }
    }
    
    • 模拟网络请求的回调接口Callback
    public interface Callback {
        public void onSuccess(User user);
        public void onFailure(String message);
    }
    
    • 可以看到Controller层中的MainActivity,包含的逻辑有:
      • 获取view的引用,监听view的交互回调,获取用户的输入内容;
      • 发送网络请求,获取用户数据,处理请求结果的回调;
      • 根据请求的结果,更新界面;
    • MainActivity负责的职责太多,随着业务逻辑的复杂化,MainActivity的代码会变得非常臃肿,我们需要对其进行代码的拆分,将获取模型数据的逻辑,转移到Model层中,下面使用MVP架构,进行改造;
    MVP -- 登录
    • 为了实现代码的拆分,将原来的MainActivity,按职责拆分成以下三个类:
      • MainActivity:View层,还是原来的MainActivity,不过职责变了,只负责获取view的引用,监听view的交互回调,获取用户的输入内容;
      • LoginPresent:Present层,是View层(MainActivity)与Model层(LoginModel)的中间者,持有View层与Model层的引用,负责View层与Model层之间的通信,对参数进行处理,调用Model的函数获取数据,并监听Model获取数据之后的回调,然后将获取到的数据,传递给View层,让View去更新界面;
      • LoginModel:Model层,包含User模型类,主要负责发送网络请求或者访问本地数据库,获取用户数据,最后将请求结果传给LoginPresent,然后LoginPresent通知View层更新界面;
    • 为了实现Present层与View层和Model层的解耦合,采用接口interface技术,为MainActivityLoginPresentLoginModel分别定义三个接口:IViewILoginPresenterILoginModel
    • 如果 LoginPresent直接持有MainActivity(View),那么两者之间的关系就绑定死了,如果现在需要将MainActivity替换成MainFragment就会出现报错,若 LoginPresent直接持有IView接口实现类,那么让MainFragment去实现IView接口,就能完成替换,同理定义的ILoginPresenterILoginModel这两个接口也是为了解耦;
    • Model层:包含数据模型User,处理登录请求的业务逻辑类LoginModel,其实现了ILoginModel接口;
    • 数据模型User的代码同上,LoginModel的代码如下:
    import android.os.Handler;
    import android.os.Looper;
    
    public class LoginModel implements ILoginModel {
        @Override
        public void login(final String userName, final String password, final Callback callback) {
            //模拟耗时操作 网络请求
            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                @Override
                public void run() {
                    User user = new User("yanzi",30);
                    callback.onSuccess(user);
                }
            },3000);
        }
    }
    
    • Model层接口ILoginModel,定义如下:
    public interface ILoginModel {
        void login(String userName, String password, Callback callback);
    }
    
    • Present层:持有View层与Model层的引用,并实现ILoginPresenter接口,代码如下:
    import com.example.loginmvp.IView;
    import com.example.loginmvp.model.Callback;
    import com.example.loginmvp.model.ILoginModel;
    import com.example.loginmvp.model.LoginModel;
    import com.example.loginmvp.model.User;
    
    public class LoginPresent implements ILoginPresenter{
    
        private IView iview;
        private ILoginModel iLoginModel;
    
        public LoginPresent(IView view) {
            this.iview = view;
            this.iLoginModel = new LoginModel();
        }
    
        @Override
        public void login(String userName, String password) {
            if (userName.isEmpty()) {
                iview.showWarnInfo("请输入用户名");
                return;
            }
            if (password.isEmpty()) {
                iview.showWarnInfo("请输入密码");
                return;
            }
    
            iview.showProgress();
            iLoginModel.login(userName, password, new Callback() {
                @Override
                public void onSuccess(User user) {
                    iview.hideProgress();
                    iview.loginSuccess(user);
                }
    
                @Override
                public void onFailure(String message) {
                    iview.hideProgress();
                    iview.loginFaliure(message);
                }
            });
        }
    }
    
    • Present层接口ILoginPresenter,定义如下:
    public interface ILoginPresenter {
        public void login(String userName,String password);
    }
    
    • View层:主要就是MainActivity,实现IView接口,代码如下:
    import androidx.appcompat.app.AppCompatActivity;
    import android.app.ProgressDialog;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.EditText;
    import android.widget.Toast;
    import com.example.loginmvp.model.User;
    import com.example.loginmvp.presenter.LoginPresent;
    
    public class MainActivity extends AppCompatActivity implements IView {
    
        private EditText userNameEt;
        private EditText passworEt;
        private ProgressDialog progressDialog;
    
        private LoginPresent presenter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            userNameEt = findViewById(R.id.user_name);
            passworEt = findViewById(R.id.password);
    
            progressDialog = new ProgressDialog(this);
            progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
            progressDialog.setCancelable(false);
            progressDialog.setMessage("请稍后...");
    
            presenter = new LoginPresent(this);
        }
    
        public void login(View view) {
            Log.e("MainActivity","登录");
            String user_name = userNameEt.getText().toString();
            String password = passworEt.getText().toString();
            presenter.login(user_name,password);
        }
    
        @Override
        public void showProgress() {
            progressDialog.show();
        }
    
        @Override
        public void hideProgress() {
            progressDialog.hide();
        }
    
        @Override
        public void loginSuccess(User user) {
            Toast.makeText(MainActivity.this,"成功!!!",Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void loginFaliure(String message) {
            Toast.makeText(MainActivity.this,"失败!!!",Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void showWarnInfo(String info) {
            Toast.makeText(MainActivity.this,info,Toast.LENGTH_SHORT).show();
        }
    }
    
    • View层接口IView,定义如下:
    import com.example.loginmvp.model.User;
    
    public interface IView {
        //显示Hud
        void showProgress();
    
        //隐藏hud
        void hideProgress();
    
        //登录成功
        void loginSuccess(User user);
    
        //登录失败
        void loginFaliure(String message);
    
        //提示信息
        void showWarnInfo(String info);
    }
    
    MVP的基类封装
    • 首先Presenter与View之间存在生命周期的关系,这个关系适应与所有的Presenter,所以将其封装到基类中BasePresenter,Presenter的生命周期的相关函数可以定义成接口规范即IBasePresenter
    • BasePresenter与View存在绑定关系,其生命周期依赖于View,所以BasePresenter会持有View的引用,为了类之间的解耦,可使用接口,定义IBaseView接口,让BasePresenter引用IBaseView接口,代码如下:
    public abstract class BasePresenter<T extends IBaseView> implements IBasePresenter<T> {
    
        protected T mView;
    
        @Override
        public void attachView(T view) {
            mView = view;
        }
    
        @Override
        public void detachView() {
            mView = null;
        }
    
        @Override
        public boolean isViewAttached() {
            return false;
        }
    }
    
    public interface IBasePresenter<T extends IBaseView> {
    
        /**
         * 依附生命view
         *
         * @param view
         */
        void attachView(T view);
    
        /**
         * 分离View
         */
        void detachView();
    
        /**
         * 判断View是否已经销毁
         *
         * @return
         */
        boolean isViewAttached();
    
    }
    
    public interface IBaseView {
    
    }
    
    • 接下来封装BaseMVPActivity,其持有Presenter,并实现IBaseView接口;
    import android.os.Bundle;
    import androidx.annotation.Nullable;
    import androidx.appcompat.app.AppCompatActivity;
    
    ///内部成员presenter 通过泛型 限制其类型
    ///接口支持继承
    ///class类支持继承
    
    ///<T extends IBasePresenter> T的类型为:实现了 继承自IBasePresenter接口的 类
    ///LoginPresent类 实现了ILoginPresenter接口 ILoginPresenter接口是继承自IBasePresenter接口的
    
    ///BaseMVPActivity的特征
    //1.拥有一个 实现了继承自IBasePresenter接口 类型的成员 mPresenter 通过泛型
    //2.实现了 IBaseView接口
    //泛型在具体使用时 指定具体的类型
    //继承关系 在具体使用时 父类指针可以指向子类对象
    public abstract class BaseMVPActivity<T extends IBasePresenter> extends AppCompatActivity implements IBaseView {
    
        protected T mPresenter;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            initPresenter();
            init();
        }
    
        protected void initPresenter() {
            mPresenter = createPresenter();
            //绑定生命周期 present的生命周期与view的生命周期同步
            if (mPresenter != null) {
                mPresenter.attachView(this);
            }
        }
    
        @Override
        protected void onDestroy() {
            if (mPresenter != null) {
                mPresenter.detachView();
            }
            super.onDestroy();
        }
    
        /**
         * 创建一个Presenter
         *
         * @return
         */
        protected abstract T createPresenter();
    
        protected abstract void init();
    }
    
    • 然后对登录涉及的相关类进行,代码改造,首先是LoginPresenter,其继承自BasePresenter且需要指定view的泛型类型为ILoginView,并实现自己定义的接口规范ILoginPresenter,代码如下:
    package com.example.loginmvp.presenter;
    
    import com.example.base.BasePresenter;
    import com.example.loginmvp.view.ILoginView;
    import com.example.loginmvp.model.Callback;
    import com.example.loginmvp.model.ILoginModel;
    import com.example.loginmvp.model.LoginModel;
    import com.example.loginmvp.model.User;
    
    public class LoginPresenter extends BasePresenter<ILoginView> implements ILoginPresenter{
    
        private ILoginModel iLoginModel;
    
        public LoginPresenter() {
            this.iLoginModel = new LoginModel();
        }
    
        @Override
        public void login(String userName, String password) {
            if (userName.isEmpty()) {
                mView.showWarnInfo("请输入用户名");
                return;
            }
            if (password.isEmpty()) {
                mView.showWarnInfo("请输入密码");
                return;
            }
    
            mView.showProgress();
            iLoginModel.login(userName, password, new Callback() {
                @Override
                public void onSuccess(User user) {
                    mView.hideProgress();
                    mView.loginSuccess(user);
                }
    
                @Override
                public void onFailure(String message) {
                    mView.hideProgress();
                    mView.loginFaliure(message);
                }
            });
        }
    }
    
    • MainActivity继承自BaseMVPActivity,并指定Presenter的泛型类型为LoginPresenter,而LoginPresenter要求View必须是实现IBaseView接口的,所以MainActivity必须实现IBaseView接口,而自定义接口ILoginView是继承自IBaseView接口,让MainActivity实现ILoginView接口即可;
    package com.example.loginmvp.view;
    
    import android.app.ProgressDialog;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.EditText;
    import android.widget.Toast;
    
    import com.example.base.BaseMVPActivity;
    import com.example.loginmvp.R;
    import com.example.loginmvp.model.User;
    import com.example.loginmvp.presenter.LoginPresenter;
    
    public class MainActivity extends BaseMVPActivity<LoginPresenter> implements ILoginView {
    
        private EditText userNameEt;
        private EditText passworEt;
        private ProgressDialog progressDialog;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            userNameEt = findViewById(R.id.user_name);
            passworEt = findViewById(R.id.password);
    
            progressDialog = new ProgressDialog(this);
            progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
            progressDialog.setCancelable(false);
            progressDialog.setMessage("请稍后...");
        }
    
        @Override
        protected LoginPresenter createPresenter() {
            return new LoginPresenter();
        }
    
        @Override
        protected void init() {
    
        }
    
        public void login(View view) {
            Log.e("MainActivity","登录");
            String user_name = userNameEt.getText().toString();
            String password = passworEt.getText().toString();
            mPresenter.login(user_name,password);
        }
    
        @Override
        public void showProgress() {
            progressDialog.show();
        }
    
        @Override
        public void hideProgress() {
            progressDialog.hide();
        }
    
        @Override
        public void loginSuccess(User user) {
            Toast.makeText(MainActivity.this,"成功!!!",Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void loginFaliure(String message) {
            Toast.makeText(MainActivity.this,"失败!!!",Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void showWarnInfo(String info) {
            Toast.makeText(MainActivity.this,info,Toast.LENGTH_SHORT).show();
        }
    }
    

    总结

    • Java中接口interface,可用来实现类之间的解耦,功能非常的强大;
    • Java中接口interface,支持继承;
    • Java中接口interface,支持泛型,表示特定类型是实现接口interface的;

    相关文章

      网友评论

          本文标题:设计模式与架构04 -- MVP架构

          本文链接:https://www.haomeiwen.com/subject/rvpixrtx.html