MVP 模式接觸

以前查看別人的時候會看不懂別人的項目結(jié)構(gòu)犁珠,里面有個 presenter袱蜡,其實代碼勉強看得懂丝蹭,但是邏輯會感覺很混亂,所以后來學(xué)習(xí)了下 MVP 模式坪蚁,現(xiàn)在需要整理一下奔穿。

MVC 和 MVP 的區(qū)別

說起 MVP 模式不得不提起 MVC 模式,也是我們接觸最多敏晤,也應(yīng)該是最早接觸的贱田,雖然一開始的時候感覺自己寫的連 MVC 模式都談不上??。
MVC 模式的全程是 Model-View-Controller

  • Model 業(yè)務(wù)邏輯和實體對象
  • View 布局文件
  • Controller 控制器嘴脾,也就是常說的 Activity

MVC 模式在小型的項目上面很適用男摧,說白了就是簡單粗暴蔬墩,邏輯簡單,View 就是布局耗拓,實際的關(guān)于數(shù)據(jù)綁定的工作都是交給 Activity 來完成拇颅,這樣子搞得 Activity 又像 Controller 又像是 View,借用網(wǎng)上的圖來表示這種關(guān)系


image.png

也就是說由于 Activity 的職責(zé)很模糊乔询,就會導(dǎo)致 Data 和 View 的關(guān)系很亂樟插。

而如果換做是 MVP 模式的話,關(guān)系則就會清晰很多


image.png

其中 MVP 代表的是 Model-View-Presenter竿刁,其中最大的特點就是 Presenter黄锤,它是 Model 和 View 之間的橋梁,它們分別的作用如下所示:

  • View 對應(yīng)著Activity们妥,對應(yīng)著 View 的繪制和用戶之間的 ui 交互
  • Model 和在 MVC 里面的作用一樣是業(yè)務(wù)邏輯和實體對象
  • Presenter 負責(zé)完成 View 和 Model 之間的交互。

和上面的圖描述的一樣勉吻,接下來的一張圖則更加明了监婶,是一張很經(jīng)典的描述兩種模式區(qū)別的圖


image.png

總結(jié)

MVP 減少了 Activity 要做的事情,簡化了它的代碼齿桃,把許多事情放到 Presenter 里面去完成惑惶,模塊劃分清楚,層次清楚短纵,從而降低了耦合(這里的低耦合带污,我通俗的理解就是在 MVP 模式里面,View 和 Presenter 之間香到,Presenter 和 Model之間可能互相都持有引用(這里錯了鱼冀,是只能 Presenter 持有 Model),但是 View 不會持有 Presenter 的引用悠就,反之也沒有)千绪。

例子分析

這里我們拿一個登錄的例子來說這個問題,首先我們先看下這個項目架構(gòu)梗脾,是不是感覺分的很清晰荸型,Model 層,Presenter 層和 View 層都分的很清楚炸茧。

image.png

Model 層實現(xiàn)

userBean 類

public class UserBean {

    private String userName;

    private String password;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User(" + "\n" + "userName = " + userName + "\n" + "password = " + password + ")";
    }

}

定義的 LoginModel 接口規(guī)定 Model 類要實現(xiàn)的功能瑞妇,當(dāng)然是登錄,但是這里要注意的是這里面使用的 OnLoginFinishListener 這個接口是 Presenter 里面的梭冠,通過它辕狰,Presenter 才能知道是否登錄成功。

public interface LoginModel {

    void login(UserBean userBean, OnLoginFinishListener onLoginFinishListener);

}

接著是 LoginModelImpl 這個 LoginModel 的實現(xiàn)類

public class LoginModelImpl implements LoginModel {

    @Override
    public void login(UserBean userBean, final OnLoginFinishListener onLoginFinishListener) {

        final String userName = userBean.getUserName();
        final String password = userBean.getPassword();

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {

                boolean error = false;

                if (userName == null || userName.isEmpty()) {
                    onLoginFinishListener.onUserError();
                    error = true;
                }

                if (password == null || password.isEmpty()) {
                    onLoginFinishListener.onPasswordError();
                    error = true;
                }

                if (!error) {
                    onLoginFinishListener.onSuccess();
                }

            }
        }, 2000);

    }

}

View 類的實現(xiàn)

LoginView 接口控漠,定義 Acitivity 要完成哪些交互柳琢。

public interface LoginView {

    void setUserError();

    void setPasswordError();

    void onSuccess();

}

接著是這個接口的實現(xiàn)類,在這里面實例化一個 Presenter 并持有它,通過 presenter 的實例對象來完成具體的登錄和 onDestroy 里面的釋放操作柬脸,釋放掉對 view 的持有他去,也就是 activity 的持有(這里涉及內(nèi)存泄漏的知識)。同時也要實現(xiàn)一些 ui 的交互倒堕,也就是 LoginView 接口里面定義的方法灾测。

public class LoginActivity extends AppCompatActivity implements View.OnClickListener, LoginView {

    private EditText userEditText;
    private EditText passwordEditText;
    private Button loginButton;
    private LoginPresenter loginPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        userEditText = (EditText)findViewById(R.id.et_user_name);
        passwordEditText = (EditText)findViewById(R.id.et_password);
        loginButton = (Button)findViewById(R.id.btn_login);
        loginButton.setOnClickListener(this);
        loginPresenter = new LoginPresenterImpl(this);

    }

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

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_login:
                UserBean userBean = new UserBean();
                userBean.setUserName(userEditText.getText().toString());
                userBean.setPassword(passwordEditText.getText().toString());
                loginPresenter.validateUser(userBean);
                break;
        }
    }

    @Override
    public void setUserError() {
        Toast.makeText(this, "用戶名錯誤", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void setPasswordError() {
        Toast.makeText(this, "密碼錯誤", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onSuccess() {
        Toast.makeText(this, "登錄成功", Toast.LENGTH_SHORT).show();
    }

}

最重要的 Presenter 層

LoginPresenter 類,只用實現(xiàn)兩個方法垦巴,一個是登錄媳搪,一個是銷毀。

public interface LoginPresenter {

    void validateUser(UserBean userBean);

    void onDestroy();

}

之前提到的 OnLoginFinishListener

public interface OnLoginFinishListener {

    void onUserError();

    void onPasswordError();

    void onSuccess();

}

LoginPresenter 的實現(xiàn)類骤宣,這里在登錄方法里面調(diào)用 Model 的登錄秦爆,并且在登錄的回調(diào)里面調(diào)用 LoginView 的方法,通過這么做來鏈接 Model 層和 View 層憔披,由此可見對于 MVP 模式而言等限,最重要的是 Presenter 層,View 層和 Model 層只要管好自己的事芬膝,Model 層管好業(yè)務(wù)邏輯望门,View 層管好 ui 交互,而對于 presenter 來說最重要的就是處理兩者之間的關(guān)系锰霜,作為一個協(xié)調(diào)者筹误。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市癣缅,隨后出現(xiàn)的幾起案子厨剪,更是在濱河造成了極大的恐慌,老刑警劉巖友存,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丽惶,死亡現(xiàn)場離奇詭異,居然都是意外死亡爬立,警方通過查閱死者的電腦和手機钾唬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來侠驯,“玉大人抡秆,你說我怎么就攤上這事∫鞑撸” “怎么了儒士?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長檩坚。 經(jīng)常有香客問我着撩,道長诅福,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任拖叙,我火速辦了婚禮氓润,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘薯鳍。我一直安慰自己咖气,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布挖滤。 她就那樣靜靜地躺著崩溪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪斩松。 梳的紋絲不亂的頭發(fā)上伶唯,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音惧盹,去河邊找鬼乳幸。 笑死,一個胖子當(dāng)著我的面吹牛岭参,可吹牛的內(nèi)容都是我干的反惕。 我是一名探鬼主播尝艘,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼演侯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了背亥?” 一聲冷哼從身側(cè)響起秒际,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎狡汉,沒想到半個月后娄徊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡盾戴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年寄锐,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尖啡。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡橄仆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出衅斩,到底是詐尸還是另有隱情盆顾,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布畏梆,位于F島的核電站您宪,受9級特大地震影響奈懒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜宪巨,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一磷杏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧揖铜,春花似錦茴丰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至龄寞,卻和暖如春汰规,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背物邑。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工溜哮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人色解。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓茂嗓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親科阎。 傳聞我的和親對象是個殘疾皇子述吸,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容