MVC、MVP、MVVM

MVC

1.Model、View、Controller,在Android中Activity以及Fragment相当于这里的Controller,布局文件Layout相当于View,而Model相当于数据库的数据读取,网络数据的获取对应的模型。Controller作为一个媒介,处于View与Model之间,而Model与View有着紧密的联系,耦合性很高。

YQ5Ly8.png

2.在Android中MVC还是有一定的优点的,上手容易,便于理解,也许没有看到多类似的字眼,但实际项目已经潜移默化的使用了。层次划分稍微明显,虽然Controller有时候充当了View的角色,总体来说还算整洁。也正因为Controller任务太过繁重,并且Model与View耦合度过高。另外既然Activity充当了Controller的角色,当Activity销毁时,稍不注意便会伴随着内存泄漏的风险。

MVP

1.MVP是从MVC演变而来,在安卓中区别于MVC,Activity充当了View的角色,Model数据模型,并且Model与View实现了完全解耦。当然这中架构模式还有另一个变体,Presenter这个角色要么充当一个媒介不做繁重的逻辑控制,要么充当所有的逻辑操作。
YQjNbq.png

View接收用户的操作,并通知到Presenter
Presenter接收到View层的通知,控制Model层进行业务逻辑的处理
Presenter逻辑处理完毕再次封装到Model层
收到Model的完成通知时(回调),更新View层

其中Presenter与View,Presenter与Model是双向通信的,而Model与View实现了完全解耦。

优点:View与Model完全解耦,分层严谨,处理逻辑都交由Presenter(或者Presenter完全不处理逻辑,Model处理逻辑),定位bug方便,便于单元测试。

2.通用架构写法:
YGQ6gK.png

基础类的实现BaseModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.example.mvp.base;

/**
* Created by Sai
* 接收到Presenter层下发的任务
* model与P层通过公用协议通信(protocol)
*/
public abstract class BaseModel<P extends BasePresenter, PROTOCOL> {

protected P presenter;

public BaseModel(P presenter) {
this.presenter = presenter;
}

public abstract PROTOCOL getProtocol();
}

BasePresenter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.example.mvp.base;

import java.lang.ref.WeakReference;

/**
* Created by Sai
* presenter基类
*/
public abstract class BasePresenter<V extends BaseView, M extends BaseModel, PROTOCOL> {

protected M model;

/**
* 对view层的持有使用弱引用
*/
private WeakReference<V> weakReference;

public abstract PROTOCOL getProtocol();

public BasePresenter() {
this.model = getModel();
}

/**
* 获取View P--V
* @return view
*/
public V getView() {
if (null != weakReference) {
return weakReference.get();
}
return null;
}

public abstract M getModel();

public void bindView(V view) {
weakReference = new WeakReference<>(view);
}

public void unBindView() {
if (null != weakReference) {
weakReference.clear();
weakReference = null;
}
}
}

BaseView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.example.mvp.base;

import android.app.Activity;
import android.os.Bundle;

import androidx.annotation.Nullable;

/**
* Created by Sai
*/
public abstract class BaseView<P extends BasePresenter, PROTOCOL> extends Activity {
protected P presenter;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/**
* 弱引用
*/
presenter = getPresenter();

/**
* bind
*/
presenter.bindView(this);
}

/**
* 通知P层实现的具体需求
*/
public abstract PROTOCOL getProtocol();

/**
* 从子类中获取具体的协议
*/
public abstract P getPresenter();

/**
* 异常处理(P)
*/
public void error(Exception e) {

}

@Override
protected void onDestroy() {
super.onDestroy();
presenter.unBindView();
}
}

BaseEntity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.example.mvp.bean;

/**
* Created by Sai
*/
public class BaseEntity {

private int code;

private boolean success;

private String error;

public int getCode() {
return code;
}

public void setCode(int code) {
this.code = code;
}

public boolean isSuccess() {
return success;
}

public void setSuccess(boolean success) {
this.success = success;
}

public String getError() {
return error;
}

public void setError(String error) {
this.error = error;
}

@Override
public String toString() {
return "BaseEntity{" +
"code=" + code +
", success=" + success +
", error='" + error + '\'' +
'}';
}
}

普通的JavaBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.example.mvp.bean;

/**
* Created by Sai
*/
public class UserInfo extends BaseEntity {

private int age;

private String name;

public UserInfo() {

}

public UserInfo(int age, String name) {
this.age = age;
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "UserInfo{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}

Login模块-LoginModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.example.mvp.login;

import com.example.mvp.base.BaseModel;
import com.example.mvp.bean.UserInfo;

/**
* Created by Sai
*/
public class LoginModel extends BaseModel<LoginPresenter, LoginProtocol.Model> {

public LoginModel(LoginPresenter presenter) {
super(presenter);
}

@Override
@SuppressWarnings("unchecked")
public LoginProtocol.Model getProtocol() {
return (name, passWord) -> {
if (name.equals("我是名字") && passWord.equals("我是密码")) {
presenter.getProtocol().responseResult(new UserInfo(18, "Sai"));
} else {
presenter.getProtocol().responseResult(null);
}
};
}
}

LoginPresenter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.example.mvp.login;

import com.example.mvp.LoginActivity;
import com.example.mvp.base.BasePresenter;
import com.example.mvp.bean.UserInfo;

/**
* Created by Sai
*/
public class LoginPresenter extends BasePresenter<LoginActivity, LoginModel, LoginProtocol.Presenter> {

@Override
public LoginProtocol.Presenter getProtocol() {
/**
* 接收View层的需求,并将需求分配到特定的Model去完成
*/
return new LoginProtocol.Presenter<UserInfo>() {
@Override
public void requestLogin(String name, String passWord) {
/**
* 几种形式:P层处理所有的需求(P层的逻辑变得繁重),或者P层只做分发任务(可以是功能模块library),
* 当然架构不是一成不变的,具体业务应该选择合适的模式。
*/

/** 一、p层自己处理 */
if (name.equals("我是名字") && passWord.equals("我是密码")) {
responseResult(new UserInfo(18, "Sai"));
} else {
responseResult(null);
}

/** 二、model层处理 */
// try {
// model.getProtocol().executeLogin(name, passWord);
// } catch (Exception e) {
// e.printStackTrace();
// }
}

@Override
public void responseResult(UserInfo userInfo) {
/**
* 将得到的结果通知到view层
*/
getView().getProtocol().result(userInfo);
}
};
}

@Override
public LoginModel getModel() {
return new LoginModel(this);
}
}

LoginProtocol

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.example.mvp.login;

import com.example.mvp.bean.BaseEntity;

/**
* Created by Sai
* 将Presenter层Model层View层共同的业务封装成接口
* 通用的协议规范(以登录为例)
*/
public interface LoginProtocol {

/**
* model层中
*/
interface Model {
void executeLogin(String name, String passWord) throws Exception;
}

/**
* 返回结果通知到view层
*/
interface View<T extends BaseEntity> {
void result(T t);
}

/**
* P层的协议
*/
interface Presenter<T extends BaseEntity> {
void requestLogin(String name, String passWord);

void responseResult(T t);
}
}

LoginActivity(View)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package com.example.mvp;

import android.os.Bundle;
import android.widget.Toast;

import androidx.databinding.DataBindingUtil;

import com.example.mvp.base.BaseView;
import com.example.mvp.bean.UserInfo;
import com.example.mvp.databinding.ActivityLoginBinding;
import com.example.mvp.login.LoginPresenter;
import com.example.mvp.login.LoginProtocol;

public class LoginActivity extends BaseView<LoginPresenter, LoginProtocol.View<UserInfo>> {

private ActivityLoginBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_login);

initClickListener();
}

private void initClickListener() {
binding.tvLogin.setOnClickListener(v ->
presenter.getProtocol().requestLogin(
binding.etName.getText().toString(),
binding.etPwd.getText().toString()));
}

@Override
public LoginProtocol.View<UserInfo> getProtocol() {
/**面向接口*/
return userInfo -> {
if (null != userInfo) {
Toast.makeText(LoginActivity.this, userInfo.toString(), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(LoginActivity.this, "登录失败", Toast.LENGTH_LONG).show();
}
};
}

@Override
public LoginPresenter getPresenter() {
return new LoginPresenter();
}
}

Tips

1.MVP的架构模式还是存在其他变体,当然实际的开发过程中不应该为了架构而架构;要考虑的实际问题很多,应该配合实际的业务需求,考虑到扩展性选择合理的方案。另外合理或许仅仅满足于某一个特定的时期,随着业务的的不断发展,架构模式总是在不断精进的。重要是这种思想领会。

MVVM

1.MVP的升级版,Model—View-ViewModel,同样实现了View与Model之间的解耦,配合Google的data-bindding,由于data-bindding的双向通信,相当于减轻了原MVP中P层任务逻辑,但是MVVM也是有自身的不足,如调用变得复杂,ViewModel同样会变得繁杂。bug传递较深,难以定位。

Android Architecture Components(AAC)

1.Google推荐的架构模型(模型驱动):
YGGkS1.md.jpg
2.现在使用的就是这种架构模式,总体还是挺香的。

官方推荐

1.避免将应用的入口指定为数据源。
2.在应用的各个模块之间设定明确定义的职责界限。
3.尽量少公开每个模块中的代码。
4.考虑如何使每个模块可独立测试。
5.专注于应用的独特核心,以使其从其他应用中脱颖而出。
6.保留尽可能多的相关数据和最新数据。
7.将一个数据源指定为单一可信来源。

这个功能是摆设,看看就好~~~