框架模式笔记:MVC 与MVP框架(完)

来源:互联网 发布:淘宝包邮退货邮费规则 编辑:程序博客网 时间:2024/06/07 03:21

注:部分内容参考了http://blog.csdn.net/jdsjlzx/article/details/51174396
MVC模块分析:
M:model,模型层,数据源,Android中一般对应JAVABean,DAO,本地的数据文件或者网络获取的数据内容。
V:view,视图层,负责数据的显示,在Android中 视图层一般由XML担任。
C:controller,控制层,控制数据如何显示在view上,在Android中一般由Activity担任。
框架图:
这里写图片描述

MVC之间的联系:
比如你的界面有一个按钮,按下这个按钮去网络上下载一个文件,这个按钮是view层的,是使用xml来写的,而那些和网络连接相关的代码写在其他类里。比如你可以写一个专门的networkHelper类,这个就是model层,那怎么连接这两层呢?是通过button.setOnClickListener()这个函数,这个函数就写在了activity中,对应于controller层

优点:

  • 容易理解
  • 逻辑清晰,分工明确(前端专注界面,后端专注业务逻辑)
  • 松耦合

缺点:

  • 由于MVC将程序分为3个部分,意味着同一个工程将包含更多的文件。对于小型项目,MVC会导致更大的工作量和更高的复杂性。

    实例:

M:data.xml

<?xml version="1.0" encoding="utf-8"?><resources>    <string-array name="data">        <item>AAAAA</item>        <item>BB</item>        <item>CCC</item>        <item>VVVV</item>        <item>DDDD</item>        <item>FGGGGGGGGGGGGGG</item>        <item>FDSGSD</item>        <item>GDDF</item>        <item>SDSSSSSSSSSS</item>        <item>SSSS</item>    </string-array></resources>

V:list_item.xml

<?xml version="1.0" encoding="utf-8"?><TextView xmlns:android="http://schemas.android.com/apk/res/android"    android:padding="20dp"    android:textColor="#0F0"    android:layout_width="wrap_content"    android:layout_height="wrap_content"></TextView>

C:MainActivity

 public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        ListView listView = new ListView(this);        listView.setBackgroundColor(Color.WHITE);        setContentView(listView);        String[] s = getResources().getStringArray(R.array.data);        ArrayAdapter adapter = new ArrayAdapter(this, R.layout.list_item, s);        listView.setAdapter(adapter);    }}

MVC的思考
MVC存在缺陷:问题就在于xml作为view层,控制能力实在太弱了,你想去动态的改变一个页面的背景,或者动态的隐藏/显示一个按钮,这些都没办法在xml中做,只能把代码写在activity中,造成了activity既是controller层,又是view层的这样一个窘境。大家回想一下自己写的代码,如果是一个逻辑很复杂的页面,activity或者fragment是不是动辄上千行呢?这样不仅写起来麻烦,维护起来更是噩梦。

MVC还有一个重要的缺陷,大家看上面那幅图,view层和model层是相互可知的,这意味着两层之间存在耦合,耦合对于一个大型程序来说是非常致命的,因为这表示开发,测试,维护都需要花大量的精力

MVP模块分析
P:Presenter
交互中间人:Presenter主要作为沟通View与Model的桥梁,它从Model层检索数据后,通过接口的形式将View层需要的数据返回给View层,使得View与Model之间没有耦合,也将业务逻辑从View角色上抽离出来。

V:View
用户界面:View通常是指Activity、Fragment或者某个View控件。它含有一个Presenter成员变量。通常View需要实现一个逻辑接口,将View上的操作转交给Presenter进行实现,最后,Presenter 调用View逻辑接口将结果返回给View元素。

M:Model
数据的存取:Model 角色主要是提供数据的存取功能。Presenter 需要通过Model层存储、获取数据,Model就像一个数据仓库。更直白的说,Model是封装了数据库DAO或者网络获取数据的角色,或者两种数据方式获取的集合。

框架图:这里写图片描述

MVC VS MVP:
从图中就可以看出,最明显的差别就是view层和model层不再相互可知,完全的解耦,取而代之的presenter层充当了桥梁的作用,用于操作view层发出的事件传递到presenter层中,presenter层去操作model层,并且将数据返回给view层,整个过程中view层和model层完全没有联系。看到这里大家可能会问,虽然view层和model层解耦了,但是view层和presenter层不是耦合在一起了吗?其实不是的,对于view层和presenter层的通信,我们是可以通过接口实现的,具体的意思就是说我们的activity,fragment可以去实现实现定义好的接口,而在对应的presenter中通过接口调用方法。不仅如此,我们还可以编写测试用的View,模拟用户的各种操作,从而实现对Presenter的测试。这就解决了MVC模式中测试,维护难的问题。

MVP案例:
参考自鸿洋MVP

结构图:
这里写图片描述

Model层:(对应于Activity,负责View的绘制以及与用户交互)
UserBean:

public class UserBean {    private String name;    private String pass;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getPass() {        return pass;    }    public void setPass(String pass) {        this.pass = pass;    }}

业务逻辑部分(biz就是business哦,我也是才知道-。-)
接口类

public interface ILogin {    void login(String name,String pass,ILoginListener listener);}

监听

public interface ILoginListener {    void LoginSuccess(UserBean user);    void LoginFailed();}

接口实现类

public class LoginImpl implements ILogin {    @Override    public void login(final String name, final String pass, final ILoginListener listener) {        Thread thread = new Thread() {            @Override            public void run() {                try {                    Thread.sleep(1500);                } catch (InterruptedException e) {                    e.printStackTrace();                }                if (name.equals("chj") && "123".equals(pass                )) {                    UserBean user = new UserBean();                    user.setName(name);                    user.setPass(pass);                    listener.LoginSuccess(user);                } else {                    listener.LoginFailed();                }            }        };        thread.start();    }}

这个Listener我也是看了好久才知道作用的,在V层调用P层的接口的时候,P层的接口其实调用的是M层的接口,P层调用接口时会触发监听器,M层通过回调告诉P调用的结果,然后由P调用V封装的接口做UI动作更新。(如果刚开始看不懂,请看过整体后再看)

M层完工!

View层:(业务逻辑和实体模型)
先定义View的接口类,接口主要看UI要进行哪些更新,比如如何和用户交互,如何优化操作,如何进行与P层进行逻辑交互等等。

public interface IView_Login {    public String getName();    public String getPass();    public void hideProcess();    public void showProcess();    public void clearName();    public void clearPass();    public void showSuccess();    public void showFailed();    public void enablebtns();    public void disablebtns();}

根据接口类完成Activity:

public class MainActivity extends AppCompatActivity implements IView_Login {    Button btnLogin, btnClear;    ProgressBar progress_login;    EditText edtpass, edtname;    LoginPresenter logPresenter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initView();        btnClear.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                logPresenter.clear();            }        });        btnLogin.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                logPresenter.Login();            }        });    }    private void initView() {        logPresenter = new LoginPresenter(this);        btnClear = (Button) findViewById(R.id.btnclear);        btnLogin = (Button) findViewById(R.id.btnlogin);        progress_login = (ProgressBar) findViewById(R.id.progress_login);        edtname = (EditText) findViewById(R.id.edtname);        edtpass = (EditText) findViewById(R.id.edtpass);    }    @Override    public String getName() {        return edtname.getText().toString().trim();    }    @Override    public String getPass() {        return edtpass.getText().toString().trim();    }    @Override    public void hideProcess() {        progress_login.setVisibility(View.INVISIBLE);    }    @Override    public void showProcess() {        progress_login.setVisibility(View.VISIBLE);    }    @Override    public void clearName() {        edtname.setText("");    }    @Override    public void clearPass() {        edtpass.setText("");    }    @Override    public void showSuccess() {        Toast.makeText(this, "login success", Toast.LENGTH_SHORT).show();    }    @Override    public void showFailed() {        Toast.makeText(this, "login failed", Toast.LENGTH_SHORT).show();    }    @Override    public void enablebtns() {        btnClear.setEnabled(true);        btnLogin.setEnabled(true);    }    @Override    public void disablebtns() {        btnClear.setEnabled(false);        btnLogin.setEnabled(false);    }}

click事件是需要与Presenter交互的,它就决定了Presenter要有哪些接口。
View层完工!

Presenter层:(负责完成View于Model间的交互)
Presenter是用作Model和View之间交互的桥梁,那么应该有什么方法呢?主要看View的需求

public class LoginPresenter {    ILogin iLogin;    IView_Login iView_login;    Handler myHandler = new Handler();    public LoginPresenter(IView_Login iView_login) {        this.iView_login = iView_login;        this.iLogin = new LoginImpl();    }    public void Login(){        iView_login.disablebtns();        iView_login.showProcess();        iLogin.login(iView_login.getName(), iView_login.getPass(), new ILoginListener() {            @Override            public void LoginSuccess(UserBean user) {                myHandler.post(new Runnable() {                    @Override                    public void run() {                        iView_login.hideProcess();                        iView_login.showSuccess();                        iView_login.enablebtns();                    }                });            }            @Override            public void LoginFailed() {                myHandler.post(new Runnable() {                    @Override                    public void run() {                        iView_login.hideProcess();                        iView_login.showFailed();                        iView_login.enablebtns();                    }                });            }        });    }    public void clear(){        iView_login.clearName();        iView_login.clearPass();    }}

presenter完工!

另外贴上xml吧

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context="com.example.caihuijian.test.view.MainActivity">    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_alignParentBottom="true"        android:orientation="horizontal">        <Button            android:id="@+id/btnlogin"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginLeft="10dp"            android:layout_marginRight="10dp"            android:layout_weight="1"            android:text="Login" />        <Button            android:id="@+id/btnclear"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginLeft="10dp"            android:layout_marginRight="10dp"            android:layout_weight="1"            android:text="Clear" />    </LinearLayout>    <EditText        android:id="@+id/edtname"        android:layout_width="200dp"        android:layout_height="wrap_content"        android:layout_alignParentEnd="true"        android:layout_alignParentTop="true"        android:layout_marginRight="50dp"        android:hint="@string/hint_name"        android:inputType="textPersonName" />    <EditText        android:id="@+id/edtpass"        android:layout_width="200dp"        android:layout_height="wrap_content"        android:layout_alignParentEnd="true"        android:layout_below="@+id/edtname"        android:layout_marginRight="50dp"        android:hint="@string/hint_pass"        android:inputType="numberPassword" />    <TextView        android:id="@+id/uname"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignBaseline="@+id/edtname"        android:layout_alignBottom="@+id/edtname"        android:layout_alignParentStart="true"        android:text="@string/uname" />    <TextView        android:id="@+id/upass"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignBaseline="@+id/edtpass"        android:layout_alignBottom="@+id/edtpass"        android:layout_alignParentStart="true"        android:text="@string/upass" />    <ProgressBar        android:id="@+id/progress_login"        style="@android:style/Widget.ProgressBar.Large"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_centerHorizontal="true"        android:layout_centerVertical="true"        android:visibility="invisible" /></RelativeLayout>

结合实例再分析:
MVP之间的关系:M-数据和业务逻辑处理;V-界面显示:Activity;P-调用View接口 使用Model接口实现类与Model交互,Presenter内部含有View的接口实例和Model接口实现类的实例。

这是个人理解的MVP结构:
这里写图片描述

参考链接:
http://blog.csdn.net/jdsjlzx/article/details/51174396
http://blog.csdn.net/lmj623565791/article/details/46596109
如有错误或者其他意见,欢迎讨论和吐槽。

1 0