从最简单的HelloWorld理解MVP模式

  大多数编程语言相关的学习书籍,都会以hello,world这个典型的程序作为第一个示例。作为Android应用开发者,无论使用eclipse还是用android studio,在新建项目的时候,一直按IDE默认选择项,下一步进行下去,就会创建出一个可以运行的hello,world应用程序。对于这个程序,可以认为是采用MVC模式,对应关系为:

  • View:对应于布局文件
  • Model:业务逻辑和实体模型
  • Controller:对应于Activity

    但是数据绑定、事件处理(hello world程序没有)的代码都在Activity中,Activity看起来既担任了View的角色,又担任了Controller的角色。这样随着程序业务逻辑越来越复杂,Activity中的代码就会越来越多,最终结果就是程序的耦合度越来越高,程序修改和维护越来越难。于是MVP模式的优点就显示出来了。下面我就以这个最简单的程序,来谈谈我对mvp模式的理解。

  先上代码:

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

    <TextView
        android:id="@+id/tv_show"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

    <Button
        android:id="@+id/btn_test"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="测试"/>

</LinearLayout>

  布局文件很简单,一个 TextView ,程序运行显示 “Hello World!”。这里我增加了一个Button,点击Button,开始倒计时10秒钟,以此来模拟一些耗时的操作,10秒钟后,TextView显示"Hello MVP!"。再看java代码,在MVC模式下,我们直接在 Activity 中通过 setText 方法,就可以给 TextView 设置显示的内容。MVP模式相对于MVC模式来说,就是将Controller这部分从Activity中分离出来,让Activity只担任View的角色,View和Model之间的桥梁作用由 presenter 来承担,从而达到解耦的目的。具体的方法就是通过接口回调来实现。下面是时候展现真正的步骤了:

  首先定义一个接口,就叫 IShowView吧,里面有一个 show 方法,用于给TextView设置显示内容

package com.example.joy.mvptest;

public interface IShowView {
    void show(String str);
}

  MainActivity实现上述接口:

package com.example.joy.mvptest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity implements IShowView, View.OnClickListener {

    private TextView mTvShow;
    private Button mBtnTest;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTvShow = (TextView) findViewById(R.id.tv_show);
        mBtnTest = (Button) findViewById(R.id.btn_test);
        mBtnTest.setOnClickListener(this);

    }

    @Override
    public void show(String str) {
        mTvShow.setText(str);
    }

    @Override
    public void onClick(View v) {
        if(v.getId() == R.id.btn_test) {

        }
    }
}

  代码很简单。MainActivity实现接口中的show方法,即为TextView赋值。Button的点击事件暂时没有写。

  其次,presenter模块也要定义一个接口,与 MainActivity 实现的接口提供类似的方法,就叫 IPresenter 吧:

package com.example.joy.mvptest.presenter;

public interface IPresenter {
    void show();
}

  注意,这个接口里的 show 方法没有参数,和前面 IShowView 中的方法签名不一样,当然,你也可以不命名为 show ,方法名可以自己随便起。这里的方法参数完全是根据实际需要来确定。有了接口,当然还需要有接口的实现类,命名为 PresenterComl :

package com.example.joy.mvptest.presenter;

import android.os.AsyncTask;
import android.os.SystemClock;
import android.util.Log;

import com.example.joy.mvptest.IShowView;

public class PresenterComl implements IPresenter {
    private IShowView iShowView;

    public PresenterComl(IShowView iShowView) {
        this.iShowView = iShowView;
    }

    @Override
    public void show() {
        new AsyncTask<Void, Void, Void>() {

            @Override
            protected void onPostExecute(Void aVoid) {
                super.onPostExecute(aVoid);
                Log.d("joy99", "下载完成。");
                iShowView.show("Hello,MVP!");
            }

            @Override
            protected Void doInBackground(Void... params) {
                for (int i = 0; i < 10; i++) {
                    Log.d("joy99", "正在下载...预计剩余时间 " + (10 - i) + "秒");
                    SystemClock.sleep(1000);
                }
                return null;
            }
        }.execute();

    }
}

   此处我用了一个异步任务。将倒计时打印出来,模拟一些耗时的数据操作,比如网络请求等等。该类中声明了一个IShowView接口的实现类的对象,iShowView,倒计时完成,调用iShowView的show方法,将“结果”传递过去,典型的接口回调的用法。

  剩下的最后一步就很清晰了,在 MainActivity 中定义 PresenterComl 类的对象 iPresenter,然后,在Button的点击事件中,调用 iPresenter 的show方法。注意构造方法中MainActivity本身,作为实现 IShowView 的类的对象传递进去。修改后的 MainActivity 类代码如下:

package com.example.joy.mvptest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.example.joy.mvptest.presenter.IPresenter;
import com.example.joy.mvptest.presenter.PresenterComl;

public class MainActivity extends AppCompatActivity implements IShowView, View.OnClickListener {

    private TextView mTvShow;
    private Button mBtnTest;

    private IPresenter iPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTvShow = (TextView) findViewById(R.id.tv_show);
        mBtnTest = (Button) findViewById(R.id.btn_test);
        mBtnTest.setOnClickListener(this);

        iPresenter = new PresenterComl(this);
    }

    @Override
    public void show(String str) {
        mTvShow.setText(str);
    }

    @Override
    public void onClick(View v) {
        if(v.getId() == R.id.btn_test) {
            iPresenter.show();
        }
    }
}

   上面黄色底纹的代码就是这最后一步,将Presenter部分与Activity建立关联。

  OK,通过这样一个小程序将MVP模式分析了一下,它的本质其实就是接口回调。当然,对于这样一个小的不能再小的程序来说,用MVP模式,确实看起来更复杂了。但是代码逻辑复杂了,MVP模式的优势就显示出来了。最后总结一下:

  使用MVP模式会使得代码多出一些接口,但是使得代码逻辑更加清晰,尤其是在处理复杂界面和逻辑时,我们可以对同一个activity将每一个业务都抽离成一个Presenter,这样代码既清晰、逻辑明确又方便我们扩展。当然如果我们的业务逻辑本身就比较简单的话使用MVP模式就显得没那么必要。所以我们不需要为了用它而用它,具体的还是要要业务需要。

  

时间: 2024-08-08 03:02:53

从最简单的HelloWorld理解MVP模式的相关文章

用最简单的例子理解备忘录模式(Memento Pattern)

简单来说,备忘录模式就是支持回退操作.假设让一个Notepad支持回退操作,如何实现呢? 首先需要一个备忘录类. public class Memento { private string _msg; public Memento(string msg) { _msg = msg; } public string GetText() { return _msg; } } 以上,○ 构造函数在Nodepad每次记录信息的时候调用,Nodepad所记录的信息最终通过该构造函数赋值给了_msg字段.○

用最简单的例子理解复合模式(Composite Pattern)

在显示树形结构时,复合模式有很好的体现.本篇显示如下部门结构: 以上,有的节点包含子节点,有的节点部包含子节点.不管是什么节点,每个节点就代表一个部门. 首先设计一个关于部门的抽象基类. public abstract class DepartmentComponent { public string Name { private set; get; } public DepartmentComponent(string name) { this.Name = name; } public vi

用最简单的例子理解迭代器模式(Iterator Pattern)

迭代器模式的需求来自:需要对一些集合进行迭代,而迭代的方式可能有很多种. 说到迭代,动作大致包括设置第一个位置,获取下一个位置元素,判断是否迭代结束,获取当前位置元素,大致就这么些.把这些迭代动作封装到一个接口中. public interface IIterator { void First(); string Next(); bool IsDone(); string Current(); } 在现实场景中,迭代的方式可能有很多种,先实现一种迭代方式,实现IIterator接口. publi

用最简单的例子理解命令模式(Command Pattern)

假设想让遥控器控制电灯的开关.电视机的开关和切换,该如何做? 所有的开.关.切换都是遥控器发出的指令,把这些指令统一抽象成一个接口. public interface IControl { void Execute(); } 把电灯.电视机抽象成类. public class Tv { public void TurnOn() { Console.WriteLine("电视机打开了"); } public void TurnOff() { Console.WriteLine("

用最简单的例子理解模板方法模式(Template Method Pattern)

假设要做一道红烧肉,做法有很多,在不同的做法中都有相同的部分,比如都要放油.放肉.放调料等.也有不同之处,比如有些做法放可乐,有些做法放甜蜜酱,等等. 先提炼出一个抽象类,该类不仅有制作红烧肉的各个步骤,而且还把各个步骤归纳到另一个方法,我们把这个方法称作模版方法.另外,在模版方法中,对于一些不确定的方面先用抽象方法. public abstract class HongShaoRou { public void MakeHongShaoRou() { You(); Rou(); Others(

浅谈Android中的MVC与MVP模式

使用MVC或者MVP模式会增加很多的类,但是确可以让代码结构变得清晰,方便了后期维护拓展方便.把数据层跟视图层分离,处理事务的逻辑单独的放在一个类中,让Activity仅仅具有展示功能. 下面我们就MVC模式跟MVP模式进行分别讲解,总之来说各有利弊.在实际的开发中,我们根据实际情况进行取舍.个人认为MVP模式更简单一些,因为MVP模式中会把部分逻辑Activity中,但是这就造成了Activity的相对繁琐,没有实现完全的隔离.而我们采用的MVC模式则是更好的处理了这个问题,但是在应用的过程中

android MVP模式简单介绍

原文 http://zhengxiaopeng.com/2015/02/06/Android%E4%B8%AD%E7%9A%84MVP/ 前言 MVP作为一种MVC的演化版本在Android开发中受到了越来越多的关注,但在项目开发中选择一种这样的软件设计模式需保持慎重心态,一旦确定 使用MVP作为你App的开发模式那么你就最好坚持做下去,如果在使用MVP模式开发过程中发现问题而且坑越来越大,这时你想用MVC等来重新设计的话基 本上就等于推倒重来了.要知道在Android上MVP在现在为止并没有统

MVP模式(2) 你真的理解下抽象类和接口吗??

转载请注明出处:王亟亟的大牛之路 礼拜5下午,有一些小伙伴在讨论关于"我对MVP的理解啊","我对RxJava,RxAndroid的理解啊"等等.在交流中发现,其实我们往往在实际开发中有意无意的都可能出现某个类特别的繁杂,代码特别的多,而且其实很多都是重复的,但是又没有办法,诸如一大堆回调. 可能在项目构建之初,想着我要如何如何去实现,如何如何优化代码结构,逻辑等等,可是因为理解或者业务繁重等各个因素,导致到后来还是挤成一坨龙猫,像这样(麦麦胖的脚都看不见了,臃肿,

深入理解IOC模式及Unity简单应用

研究了下,有几篇博客确实已经说得很清楚了 1.IoC模式:http://www.cnblogs.com/qqlin/archive/2012/10/09/2707075.html  这篇博客是通过一个播放器的例子来说明什么是依赖,依赖倒置,控制反转(IOC),最后实现依赖注入.通过Unity实现IOC容器.不错的一个例子 2.深入理解DIP.IoC.DI以及IoC容器 这个算是最通俗易懂的,手动实现了IOC容器  由浅入深 3.理解依赖注入(IOC)和学习Unity 这个也不错,特别最后介绍的挺