MVP模式的一種新嘗試

前言

在暑假的時(shí)候?qū)W習(xí)了一遍mvp開(kāi)發(fā)模式在android中的運(yùn)用。那個(gè)時(shí)候?qū)W的時(shí)候確實(shí)覺(jué)得mvp模式做安卓開(kāi)發(fā)特別清晰,代碼模塊分的特別清楚糟袁。但是在自己寫(xiě)demo的時(shí)候還是把自己有點(diǎn)繞暈了。因?yàn)閙vp模式運(yùn)用了大量的接口(面向接口編程)來(lái)實(shí)現(xiàn)view和model層的解耦。那時(shí)候甚至連設(shè)計(jì)模式都沒(méi)看攒驰,所以一下子接觸這種抽象的設(shè)計(jì)模式有點(diǎn)不適應(yīng)。雖然說(shuō)google的data-binding的不斷完善會(huì)導(dǎo)致安卓上面mvvm模式越來(lái)越火故爵,但是我覺(jué)得設(shè)計(jì)模式嘛玻粪,學(xué)習(xí)一下沒(méi)有壞處,可以提升自己的理解力诬垂。這篇博客主要講一種mvp的一種新嘗試(將activity, fragment, adapter作為presenter)劲室。

MVP

mvp模式與mvc模式最大的差別就是,它將view層跟model實(shí)現(xiàn)完全解耦结窘。所有的數(shù)據(jù)交互都在presenter層中很洋。view,model和presenter的交互通過(guò)接口,view和model的交互通過(guò)presenter隧枫。解耦的好處就是視圖層和數(shù)據(jù)層兩者互不影響喉磁,所有的邏輯都在presenter中,他作為一個(gè)中間層可以給多個(gè)view來(lái)使用官脓。完全通過(guò)接口來(lái)解耦可以提高代碼維護(hù)度协怒。

而mvc模式則是視圖層可以通過(guò)control與數(shù)據(jù)層交互也可以直接跳過(guò)control和數(shù)據(jù)層直接交互。這樣大多數(shù)時(shí)候會(huì)在view層里面new出model/bean的對(duì)象來(lái)卑笨。這樣就把兩者耦合在了一起孕暇。

傳統(tǒng)mvp

傳統(tǒng)的mvp模式是將activity或者fragment作為view層,將所有的邏輯代碼抽出到presenter(一個(gè)java類)赤兴。這是我暑假寫(xiě)的一個(gè)demo源碼 傳統(tǒng)mvp demo 芭商。

mvp1.png

可以通過(guò)我的項(xiàng)目分包看出來(lái),每一個(gè)類實(shí)現(xiàn)接口搀缠,通過(guò)接口來(lái)進(jìn)行抽象解耦铛楣,以及數(shù)據(jù)交互。

一種新思想

這個(gè)思想也是通過(guò)github上面一個(gè)翻譯的文章看來(lái)的艺普。因?yàn)閍ctivity中包含著context簸州, intent鉴竭,獲得系統(tǒng)服務(wù)等等,如果把a(bǔ)ctivity作為視圖層就應(yīng)該避免這些業(yè)務(wù)邏輯岸浑。所以將activity僅僅作為視圖層有點(diǎn)發(fā)揮不出他的真正價(jià)值搏存。所以我們考慮把a(bǔ)ctivity,fragment矢洲,adapter來(lái)作為presenter處理邏輯璧眠,用java類文件來(lái)作為視圖層。并且這樣做了之后读虏,我感覺(jué)代碼的清晰度是有提升的责静。這是我寫(xiě)的demo源碼:新mvp demo

mvp2.png

大概思路是用一個(gè)抽象類來(lái)抽出activity中必不可少的ui代碼(比如setContentView()以及初始化各種控件)盖桥。然后每一個(gè)view類文件實(shí)現(xiàn)擴(kuò)展了view層基接口的接口灾螃,這樣做的目的是為了實(shí)現(xiàn)view和baseacitivty之間的解耦。(這個(gè)確實(shí)倒騰了很久揩徊,因?yàn)槲腋杏X(jué)原文章的代碼有問(wèn)題)腰鬼。之后在抽象類里面去通過(guò)presenter返回的view文件類型,用反射獲得對(duì)象并進(jìn)行view的渲染塑荒。然后再在presenter中去處理邏輯熄赡。看代碼吧齿税!

/**
 * Created by Zane on 15/12/5.
 * 用于抽出activity中對(duì)于ui的操作代碼
 * 弄出兩個(gè)抽象方法來(lái)保證生命周期同步
 */
public abstract class BasePresentActivity<X extends V, V extends Vu> extends AppCompatActivity{

    protected V vu;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        try {
            vu = getVuClass().newInstance();
            vu.init(getLayoutInflater(), null);
            setContentView(vu.getView());
            onBindVu();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

    }

    @Override
    protected void onDestroy() {
        onDestroyVu();
        vu = null;
        super.onDestroy();

    }

    protected abstract Class<X> getVuClass();

    protected void onBindVu(){};

    protected void onDestroyVu() {};
}

首先解釋這個(gè)抽象類的兩個(gè)泛型本谜。Vu是view層的基接口,代碼如下:

/**
 * Created by Zane on 15/12/5.
 * view類的超類
 */
public interface Vu {
    void init(LayoutInflater inflater, ViewGroup container);
    View getView();
}

可以看到有兩個(gè)方法偎窘,一個(gè)用來(lái)進(jìn)行view渲染,一個(gè)是返回根視圖溜在。而泛型里面的V就是擴(kuò)展了Vu的第二層接口陌知。最后X就是實(shí)現(xiàn)了第二層接口的view類文件。這樣做的目的就是做到解耦掖肋,防止我用傳入的類文件去實(shí)例化類文件仆葡,這里應(yīng)該是去實(shí)例化接口。(用X的對(duì)象去實(shí)例化V)

然后再看onBindVu()和onDestoryVu()方法志笼,這個(gè)方法是在繼承了這個(gè)抽象類的presenter里面去實(shí)現(xiàn)的沿盅,目的是為了達(dá)到生命周期同步。

getVuClass()方法就是要獲得這個(gè)presenter對(duì)應(yīng)的view類文件類型纫溃。

/**
 * Created by Zane on 15/12/5.
 * 為了使view類和present類解藕
 */
public interface VuLoginActivity extends Vu{

    Button getButtonLogin();

    Button getButtonClear();

    EditText getEditTextAccount();

    EditText getEditTextPassword();

    void clearText();

}

這就是擴(kuò)展了Vu接口的第二層接口腰涧。看到我添加了幾個(gè)方法紊浩。

/**
 * Created by Zane on 15/12/5.
 */
public class LoginActivityViewImpl implements VuLoginActivity{

    protected View view;
    protected Button buttonLogin;
    protected Button buttonClear;
    protected EditText account;
    protected EditText password;

    @Override
    public void init(LayoutInflater inflater, ViewGroup container) {
        view = inflater.inflate(R.layout.activity_main, container, false);
        buttonLogin = (Button)view.findViewById(R.id.button_login);
        buttonClear = (Button)view.findViewById(R.id.button_clear);
        account = (EditText)view.findViewById(R.id.account);
        password = (EditText)view.findViewById(R.id.password);
    }

    @Override
    public View getView() {
        return view;
    }

    @Override
    public Button getButtonLogin() {
        return buttonLogin;
    }

    @Override
    public Button getButtonClear() {
        return buttonClear;
    }

    @Override
    public EditText getEditTextAccount() {
        return account;
    }

    @Override
    public EditText getEditTextPassword() {
        return password;
    }

    @Override
    public void clearText() {
        account.setText("");
        password.setText("");
    }
}

這里代碼也很簡(jiǎn)單啦窖铡!

public class MainActivity extends BasePresentActivity<LoginActivityViewImpl, VuLoginActivity> {

    @Override
    protected void onBindVu() {

        final User user = new User();

        vu.getButtonLogin().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String userName = vu.getEditTextAccount().getText().toString();
                String password = vu.getEditTextPassword().getText().toString();
                Toast.makeText(MainActivity.this, userName, Toast.LENGTH_SHORT).show();
                if(userName.equals(user.getUserName()) && password.equals(user.getPassword())) {
                    Intent intent = new Intent(MainActivity.this, LoginSuccessActivity.class);
                    intent.putExtra("username", userName);
                    startActivity(intent);
                }else {
                    Toast.makeText(MainActivity.this, "錯(cuò)誤", Toast.LENGTH_SHORT).show();
                }
            }
        });

        vu.getButtonClear().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                vu.clearText();
            }
        });
    }

    @Override
    protected void onDestroyVu() {
        super.onDestroyVu();
    }

    @Override
    protected Class<LoginActivityViewImpl> getVuClass() {
        return LoginActivityViewImpl.class;
    }
}

這個(gè)就是presenter疗锐。看到我在對(duì)應(yīng)的生命周期里面做了邏輯處理费彼,并且返回他對(duì)應(yīng)的view類文件滑臊。

結(jié)束語(yǔ)

MVP模式確實(shí)給項(xiàng)目維護(hù)帶來(lái)了一些便捷,但是也發(fā)現(xiàn)箍铲,相對(duì)于小的項(xiàng)目會(huì)導(dǎo)致你的代碼量迅速膨脹雇卷。所有很多人弄一些mvp的開(kāi)發(fā)框架。確實(shí)我自己也想用這種新思路來(lái)倒騰一個(gè)颠猴。但是對(duì)于大型項(xiàng)目关划,這樣的代碼膨脹并不算什么,帶來(lái)的好處絕對(duì)優(yōu)于壞處芙粱。這次學(xué)習(xí)又鞏固了一下我的設(shè)計(jì)模式祭玉。以一句話結(jié)尾:面對(duì)接口編程, 避免面對(duì)實(shí)現(xiàn)編程

未經(jīng)博主同意春畔,不得轉(zhuǎn)載該篇文章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末脱货,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子律姨,更是在濱河造成了極大的恐慌振峻,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件择份,死亡現(xiàn)場(chǎng)離奇詭異扣孟,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)荣赶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門凤价,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人拔创,你說(shuō)我怎么就攤上這事利诺。” “怎么了剩燥?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵慢逾,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我灭红,道長(zhǎng)侣滩,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任变擒,我火速辦了婚禮君珠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘娇斑。我一直安慰自己葛躏,他們只是感情好澈段,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著舰攒,像睡著了一般败富。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上摩窃,一...
    開(kāi)封第一講書(shū)人閱讀 51,482評(píng)論 1 302
  • 那天兽叮,我揣著相機(jī)與錄音,去河邊找鬼猾愿。 笑死鹦聪,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蒂秘。 我是一名探鬼主播泽本,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼姻僧!你這毒婦竟也來(lái)了规丽?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤撇贺,失蹤者是張志新(化名)和其女友劉穎赌莺,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體松嘶,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡艘狭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了翠订。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片巢音。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖尽超,靈堂內(nèi)的尸體忽然破棺而出官撼,到底是詐尸還是另有隱情,我是刑警寧澤橙弱,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站燥狰,受9級(jí)特大地震影響棘脐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜龙致,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一蛀缝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧目代,春花似錦屈梁、人聲如沸嗤练。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)煞抬。三九已至,卻和暖如春构哺,著一層夾襖步出監(jiān)牢的瞬間革答,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工曙强, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留残拐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓碟嘴,卻偏偏與公主長(zhǎng)得像溪食,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子娜扇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

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