Android MVP And MAC 001

Android MVP And MAC

面向对象原则之一:单一职责原则

MVC MVP
M Model 模型
V View 视图
C Controller 控制器
P Presenter 纽带曾,提出者

MVC

逻辑图

这里写图片描述

按照Android里面的意思 Activity相当于View,而很多时候Activity职责不单单是显示View这么简单,还有处理业务逻辑,视图显示,页面的跳转,单纯来说 业务层和显示层已经耦合在一起,不能进行分离解耦,Activity = Controller + view

单纯的MVC模型已经不试用于Android,为了适应Android 架构诞生出来MVP结构更适合Android。

其中MVC各层的职责:

Model :
模型代表着核心的业务逻辑数据。模型封装了域实体的属性和行为,并暴露出了实体的属性。

View:
视图负责转换模型并把它传递给表示层。视图应关注于如何展示数据,而不应该包含任何业务逻辑业务逻辑封装在模型中。

Controller:
控制器控制程序的逻辑,并且充当着视图和模型之间协调的角色。控制器从视图层接收用户输入的信息,然后使用模型来执行特定的操作,并把最终的结果回传给视图。

MVP

摘自百度文档

    MVP如何解决MVC的问题?
    在MVP里,Presenter完全把Model和View进行了分离,主要的程序逻辑在Presenter里实现。
    而且,Presenter与具体的View是没有直接关联的,而是通过定义好的接口进行交互,从而使得在变更View时候可以保持Presenter的不变,即重用! 
    不仅如此,我们还可以编写测试用的View,模拟用户的各种操作,从而实现对Presenter的测试--而不需要使用自动化的测试工具。 
    我们甚至可以在Model和View都没有完成时候,就可以通过编写Mock Object(即实现了Model和View的接口,但没有具体的内容的)来测试Presenter的逻辑。 
    在MVP里,应用程序的逻辑主要在Presenter来实现,其中的View是很薄的一层。因此就有人提出了Presenter First的设计模式,就是根据User Story来首先设计和开发Presenter。在这个过程中,View是很简单的,能够把信息显示清楚就可以了。
    在后面,根据需要再随便更改View,而对Presenter没有任何的影响了。 
    如果要实现的UI比较复杂,而且相关的显示逻辑还跟Model有关系,就可以在View和Presenter之间放置一个Adapter。
    由这个 Adapter来访问Model和View,避免两者之间的关联。而同时,因为Adapter实现了View的接口,从而可以保证与Presenter之间接口的不变。这样就可以保证View和Presenter之间接口的简洁,又不失去UI的灵活性。 在MVP模式里,View只应该有简单的Set/Get的方法,用户输入和设置界面显示的内容,除此就不应该有更多的内容,绝不容许直接访问Model--这就是与MVC很大的不同之处。

这里写图片描述

职责

M 负责 业务逻辑,和数据提供
Presenter 负责View和Model之间进行的交互操作。
View 负责显示相应的界面。

其中我们以一个小Demo进行试验:

一个简单的登录功能,当然网络请求只是模拟数据。

xml:

基本的XML 没有什么好看的。最简单的例子

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">


    <EditText
        android:id="@+id/et_id"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="账号" />

    <EditText
        android:id="@+id/et_password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="密码" />

    <Button
        android:id="@+id/btn_login"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="登录" />

    <TextView
        android:id="@+id/tv_login_state"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="登录状态:" />
</LinearLayout>

下面是代码部分重点:
还有件事要唠叨一下,毕竟把逻辑 显示控制分离,代码好看是好看了,增加了一些难度,第一个是代码量变多了,面向接口编程了,多出好多东西,还有一个,书写的难度增加了。写代码之前必须要考虑 要显示哪些东西,在什么地方控制它,简单来说 就是 把职责进行分离了。但是Android书写的时候职责有些地方是模糊的,比如Activity 逻辑 控制 显示 集为一体。好多人这样写吧。

我们按照MVP模式编写代码的时候,可以分为三类,
MVP
M Model 需要先定义它要做什么,然后再进行实现它,而我们的Model部分很简单,就是发送一个POST请求(模拟),然后把返回数据进行简单处理一下。

ILoginModel 这里是接口
LoginModel 这里是实现部分

V View 这里是我们只有显示的部分,也就是说只有set 和get部分
ILoginView
LoginView

P Presenter 这里就是重点看上面的图就能看出来是控制View和Model进行交互的部分,View Model交互曾
LoginPresenter

第一个部分:M 部分
写代码之前我们先理解它的职责,文章上部分有写着。
业务逻辑和数据

public interface ILoginModel {
    /**
     * 请求登录数据
     *
     * @param loginRequest
     * @param onResponse
     */
    void postLogin(LoginRequest loginRequest, OnResponse onResponse);
}

相当于Model存储提取处理数据。

public class LoginModel implements ILoginModel {
    Handler handler = new Handler(Looper.getMainLooper());

    /**
     * 模拟POST请求
     *
     * @param loginRequest
     * @param onResponse
     */
    @Override
    public void postLogin(final LoginRequest loginRequest, final OnResponse onResponse) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Map params = loginRequest.getParams();
                String userName = (String) params.get("userName");
                final String password = (String) params.get("password");

                final String str = "您的账号:" + userName + "---您的密码:" + password;

                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        onResponse.onSuccess(str, "login");
                    }
                });
            }
        }).start();


    }
}

第二部分V 部分,首先我们要理解我们到底需要在LoginActivity做什么操作,set get

也就是获取发送登录信息,和获取登录后信息进行显示

public interface ILoginView {
    /**
     * 获取用户名ID
     *
     * @return
     */
    Editable getId();
    /**
     * 获取密码输入
     *
     * @return
     */
    Editable getPassword();
    /**
     * 设置登录后状态
     *
     * @param state
     */
    void setLoginState(String state);
    Context getContext();
}

实现部分:

public class LoginActivity extends AppCompatActivity implements View.OnClickListener, ILoginView {
    private EditText mEtId, mEtPassword;
    private TextView mTvState;
    private LoginPresenter mLoginPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.login_activity);
        findViewById(R.id.btn_login).setOnClickListener(this);
        mEtId = (EditText) findViewById(R.id.et_id);
        mEtPassword = (EditText) findViewById(R.id.et_password);
        mTvState = (TextView) findViewById(R.id.tv_login_state);
        mLoginPresenter = new LoginPresenter(this);

    }


    @Override
    public void onClick(View v) {
        mLoginPresenter.requestLogin();
    }

    @Override
    public Editable getId() {
        return mEtId.getText();
    }
    @Override
    public Editable getPassword() {
        return mEtPassword.getText();
    }
    @Override
    public void setLoginState(String state) {
        mTvState.setText(state);
    }
    @Override
    public Context getContext() {
        return this;
    }
}

下面是Presenter部分了。
mLoginPresenter.requestLogin();
而我们需要点击按钮发送结果数据。

public class LoginPresenter {
    private ILoginView mILoginView;
    private ILoginModel mILoginModel;


    public LoginPresenter(ILoginView context) {
        mILoginView = (ILoginView) context;
        mILoginModel = new LoginModel();
    }


    public void requestLogin() {
        LoginRequest loginRequest = new LoginRequest();
        loginRequest.setUserName(mILoginView.getId().toString());
        loginRequest.setPassword(mILoginView.getPassword().toString());
        mILoginModel.postLogin(loginRequest, new OnResponse() {
            @Override
            public void onSuccess(String s, String url) {
                mILoginView.setLoginState(s + "网址:" + url);
            }

            @Override
            public void onailureF(Exception e) {

            }
        });
    }

}

刚接触MVP 肯定一头雾水,代码看起来真心方便,但是做起来思维有点麻烦。

首先分析一下整体结构

model
ILoginModel
LoginModel
presenter
LoginPresenter
view
ILoginVIew
LoginActivity

第一步我们应该想我们到底要做个什么东西,就拿上面Demo来说,我们要做一个这样的东西,
2个EditText 一个账号 一个密码
1个Button 负责请求登录
一个TextView 负责显示请求状态信息

整体需求就出来了。

我们IView需要放置
1:获取账号密码接口 get
2:设置请求状态接口 set
我们的Model,处理,存储,获取数据
1:请求登录接口任务
3:处理一些数据
Presenter 负责Model 和View之间的交互

Presenter
存储IView的接口
存储IModel的接口
IView 请求登录的时候调用IModel接口
返回结果Model处理完成以后 直接set到IView接口上。

本人也是一个小菜鸟,错误希望大家指点出来。

Demo 下载

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值