从 HelloWorld 来重新认识 MVC、MVP

47 篇文章 0 订阅
6 篇文章 0 订阅

本文分析了 MVC、MVP 的概念,并以一个 HelloWorld 的例子来深入说明。

一、明确的概念

MVC、MVP 我们都知道,是一种架构模式。但它们的明确定义到底是什么呢,网上各式各样的流程图,各式各样的箭头指向,看得人头晕眼花,云里雾里。经过漫长的寻觅,我终于在这里找到一句话,解答了我的疑惑:不幸的是,MVC、MVP 都没有被广泛接受的定义

仔细想想,可不就是这样吗,MVC、MVP 只是一种思想,具体的实现方式当然不会完全一致,而这个思想唯一明确的、被广泛接受的概念只有一个,那就是:把代码分为三块

代码分为的三块:

Model:数据
View:界面
Controller/Presenter:界面和数据的管理者/控制者/主持者

从这个角度来说,MVC、MVP 其实是一样的,只是命名不同而已。

二、Android HelloWorld 的实例

以一个 Android 的 HelloWorld 的例子来说明:

public class HelloActivity extends AppCompatActivity {
    private TextView mTvHello;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_hello);
        mTvHello = findViewById(R.id.tv_hello);
        mTvHello.setText("hello world")
    }
}

这里面的 M、V、C:

“helloWorld” -> model
textView -> view
textView.setText(“helloWorld”) -> controller/Presenter

textView.setText("helloWorld") 在 Activity 中执行,所以 Activity 是 controller/Presenter,"helloWorld"textView.setText("helloWorld") 都在 Activity 中,所以它也包含了 View、model。

当 model、view 变得越来越多、越来越大,controller/Presenter (Activity)的代码就会变得很多。所以人们会很想将它们区分开(解耦),View 就是 view,Model 就是 Model,controller/Presenter 就是 controller/Presenter。

2.1 一种常见的分离方式

下面来看一种很常见的分离方式。(这就是被广为流传的 MVP 模式,为了方便理解,没有使用接口)。

Model 是最容易拆出来的:

public class HelloModel {
    public String getHelloText() {
        return "hello world";
    }
}

View:

public class HelloActivity extends AppCompatActivity {

    private TextView mTvHello;
    private HelloPresenter mPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_hello);
        mTvHello = findViewById(R.id.tv_hello);

        mPresenter = new HelloPresenter(this);
        mPresenter.setHelloText();
    }


    public void setHelloText(String helloText) {
        mTvHello.setText(helloText);
    }
}

Presenter:

public class HelloPresenter {
    private HelloModel mHelloModel;
    private HelloActivity mHelloView;

    public HelloPresenter(HelloActivity helloView) {
        mHelloView = helloView;

        mHelloModel = new HelloModel();
    }

    public void setHelloText() {
        mHelloView.setHelloText(mHelloModel.getHelloText());
    }
}

可以看出,在这种分离方式中,是将 Activity 作为 View,将操作 View、Model 的方法提到了单独的 Presenter 类中。

这样看上去貌似没有什么问题,但是总觉得哪里不太对劲。

我们看看 View (Activity)里的方法,在 onCreate 中调了 mPresenter.setHelloText(),而 mPresenter.setHelloText() 内部又调了 View(Activity)自己的 setHelloText() 方法。这不是绕了一圈又回来了吗。

既然这样,为什么 View(Activity)不直接调自己的 setHelloText() 方法呢?因为它只是一个 View,一个动作不应该由它来发起。可是通过 presenter 再去调自己的方法不还是间接地发起了一个动作吗。

产生这样的矛盾的原因就在于:onCreate() 方法天生就属于 Presenter,即 Activity 天生就是 Presenter。我们通过这种方式抽离 Presenter,只能抽取一部分,总会剩下一部分留在 Activity 里(如生命周期函数)。

所以这样的解耦仍是不彻底的,Activity 依然是 View 和 Presenter 的结合体,在某些情况下,反而会造成逻辑的冗余(如上述 Activity-Presenter-Activity 的调用链)。

有人可能会说,既然 onCreate 是属于 Presenter 的,那在 Presenter 增加一个方法 onCreate() 在 Activity 的 onCreate() 方法中调用它。这样没问题,这相当于把 Activity 的 onCreate() 方法当做了 View 的类似 onClick() 一样的回调。View 回调 onCreate()、onClick(),Presenter 执行 onCreate()、onClick() 的真实逻辑,也说得通。但问题是,Activity 中除了 onCreate(),还有太多的方法,Activity extends Context,它本来就是用来与平台交互、与应用的业务交互的。难道都提出来吗,这显然不现实。

2.2 一种更合理的分离方式

所以,既然 Presenter 提不出来,那 View 呢?好消息是,View 可以,而且很是清晰。

Model 不变,仍是原来的配方:

public class HelloModel {
    public String getHelloText() {
        return "hello world";
    }
}

View:

public class HelloView {
    private View mRootView;
    private TextView mTvHello;

    public HelloView(LayoutInflater inflater) {
        mRootView = inflater.inflate(R.layout.activity_hello, null, false);
        mTvHello = mRootView.findViewById(R.id.tv_hello);
    }

    public void setHelloText(String helloText) {
        mTvHello.setText(helloText);
    }

    public View getRootView() {
        return mRootView;
    }
}

Presenter:

public class HelloActivity extends AppCompatActivity {

    private HelloView mHelloView;
    private HelloModel mHelloModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 生成 View
        mHelloView = new HelloView(getLayoutInflater());
        setContentView(mHelloView.getRootView());
        // 生成 Model
        mHelloModel = new HelloModel();
        // 连接 View 和 Model
        mHelloView.setHelloText(mHelloModel.getHelloText());
    }
}

这种方式,将 Activity 完全作为 Presenter,而将 View 抽出去分离。Activity 不用关心 View 的任何细节,只要调 View 提供的方法就好。

mHelloView.setHelloText 的调用也只是两层调用,Activity-View,逻辑更加清晰。

以上就是我对 MVC、MVP 的浅见,如有其它见解,欢迎交流。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值