前言
手底下一直在做一個項目,從交互看起來也沒怎麼複雜,但由於歷史原因,底下有二十多個依賴工程,到目前我也沒有把依賴工程具體的東西搞明白。在代碼裏邊偶爾能看到13年的記錄,也經過了無數人的手。代碼的邏輯結構非常混亂,也許是修修補補太多了吧。哈哈,幾年後如果有人接手是不是也會這麼說我。這次迭代交互和視覺要進行一次大的改版,新的交互改變了整體的框架,所以也就乘此機會,一邊重構,一邊修改新的交互。到目前以進行一個半月,再此過程中感謝我的同事浪平哥的指導。本篇不講MVP的細節,只是簡單的說說這次重構的一些體會,鄙人愚鈍,不當之處,敬請賜教。
認識MVP
發現Android出現的一些新技術會在各種博客、微信公衆號瞬間擴散,在各大網站也會有更新。MVP已經在很久前出現了,有幸有機會能夠在項目中實戰,網上有許多的教程,還有官方的Demo,在此就不做深入分析了,僅談一談自己的理解。
MVC和MVP
MVC是我們之前的開發中一直用的開發模式,這種開發模式結構簡單,開發速度快,代碼量少。但是View和Contrl基本都在Activity中完成,造成項目中的Activity乾的事情太多,邏輯混亂,可讀性差。數據和UI糾結在一起,在迭代過程中不好修改。就像拉着一輛破車跑,實在是讓人舉步維艱。MVP的優勢在於讓數據和UI分離,V層只管UI的顯示操作,M層按照業務劃分,根據不同業務有對應不同的model完成網絡訪問、數據庫讀取等所欲的數據操作。P層是一個協調者的角色,他將從M層拿到數據,並協調分配給不同的UI,完成在界面上指定控件顯示指定的數據。這樣分工更加明確,業務之間耦合少,方便修改。
MVP最簡模型
Entity
public class Monkey(){ private name; set*** get*** }
M層
public class Model{
public Monkey getData(){ Monkey monkey=new Monkey(); //也許是訪問數據庫或者網絡等複雜的操作 monkey.setName("code"); return monkey; }
}
P層
public class Presenter{ private mIView; private mModel; public Presenter(){ mModel=new Model();//初始化一個model } public attachView(IView view){ mIView=view; } public string initData(){ return mModel.getData().getName(); } public void showView(){ mIView.show(); } }
V層
public interface IView{ void show(); } public class TestActivity extends Activity implements IView{ private TextView mTextview;//UI private String mName;//數據 private Presenter mPresenter; protect void onCreate(){ mTextView=(TextView)findeById(R.id.xxx); mPrsenter=new Presenter(); mPrsenter.attchView(this); mName=mPresenter.initData(); mPrsennter.showView(); } public void show(){ mTextView.setText(mName); } }
上述還有許多就沒有表現出來,比如當Activity銷燬的時候,應該調用Presenter的一個destory的方法銷燬P層,同樣的在M層中也要寫一個destory的方法供P層調用進行銷燬操作,這裏一可以避免數據混亂,二也是清除緩存數據,釋放內存。還有比如,我們大部分複雜一點的UI控件的顯示或者隱藏等和數據有關,這個時候我們就要把基礎的數據通過P層交給UI,將與UI相關的數據暴露在UI層中,這UI層中進行判斷等操作。如果需要進行異步加載數據,可以採用回調的方式將數據返回到UI層;
重構之路
原代碼分析
重構前接手項目有一兩個月的時間,緊張的迭代進度並沒有給我許多的時間去熟悉代碼,中間由於項目的迭代計劃出現一些問題,這個空餘的時間給了我熟悉代碼的機會,然而到後邊真正重構的時候才發現做了許多的無用功。
- 快速熟悉代碼的方法
- 首先從UI分析,可以用邏輯結構圖畫出來,每個模塊有哪些界面,這些界面對應的Activity,fragment是哪個,以便後邊看一目瞭然;
- 使用Debug調試,在有操作的等關鍵的地方打好點,一步步調試,看看程序是怎麼跑的;
- 再爛的代碼都會有他的套路,而且這個套路運用在整個程序各個地方的開發之中,我經歷的項目並不是很多,但是這個問題想想也能確定。所以,如果你對這個套路搞清楚了,這個程序在你的面前就會變得透明的,是一堆骨架。
- 需要輸出的文檔
- 功能結構圖,也就是上面說的UI界面對應的Acitivty和Fragment;
- 數據加載分析文檔,每個軟件必定會牽涉到數據,我這裏的數據加載不是網絡或者數據庫的原始數據,而是程序運行時數據的讀取、傳遞、計算等緩存的數據。我用的是用表格的形式,填寫了某一個實體類,實體類中包含的數據元素以及值。不過後來發現,這裏不要弄的太詳細,這裏邊的數據太複雜了。不要把太多的時間放在這裏,主要的目的在於把數據加載的過程瞭解清楚,重構的時候難免要動這一塊,不過真正動的時候再用Debug調試瞭解詳細信息就好了。
重構中的一些發現
寫好基礎Model業務層
在前期的準備工作中,分析得出某一些Model層業務是幾乎所有Model層公有的,這個時候我們要將一些公有的業務寫到一個基類裏邊。每個軟件都會有不同的模塊,然後我們可以在不同的模塊也寫一個基類,然後在具體的業務層的model中繼承這個基類就可以了,這樣節省了許多的代碼,也將業務分的更加清晰。
分拆原有工具類方法到Model層
在MVC模式的開發中,我們避免Activity中的代碼過多,常常將某一些共有的操作放到一個工具類中,比如數據庫的讀取,然後不同的Activity有不同的操作,這些都寫在一個工具類中,我們不好分辨誰是誰的。這些活都是由model層來乾的,我們可以通過Ctrl+G搜索這個工具類的每一個方法被誰調用了,然後分別將這些方法copy到對應的model層去。
除了 if 記得也要寫好 else
發現以前的代碼裏邊有許多容錯處理,比如常常做的是 if 某某某不等於null,然後才進行什麼操作,但是else就不管了,這樣出了問題好難查,如果我們程序寫的時候就在else 中拋出一個異常或者打一個log說明這種情況什麼爲null,出的什麼問題。這樣bug來了,找到問題也就是分分鐘的事情。爲什麼敢去重構代碼,這是一個高風險的活,因爲我在每個可能存在問題的地方都有Log說明,問題來了也好找。
從不知何處下手到感覺這只是一個套路
我的同事已經將一個獨立的新模塊完全用MVP模式寫的,爲了學習MVP模式,我這個模塊寫了一個demo,深刻覺得當無從下手的時候一定要讓自己動手。剛進行重構的時候,都不清楚該怎麼寫model,怎麼寫presenter,但是經過一段時間的改造,已經覺得沒有那麼有挑戰性了,我只是將代碼的邏輯結構進行了一些調整,基本寫的是一些框架性的東西,然後將原有的代碼copy進去,實現具體的細節。寫到後邊都覺得自己只是在進行一些體力勞動,也許是項目時間太緊,我沒有時間去優化,寫的過程中也感覺到有些地方還待改進。說的這麼多,主要是想說,重構不難,難在開頭。
不要心急,逐步重構
畢竟項目還處在迭代的計劃中,產品不可能讓我一直整代碼,所以這是一個逐步完成的工作,也許是我們原代碼實在太散了,得花點時間才動的了。不過此次重構也只是完成了大部分的模塊。所以重構也不是把代碼翻個底朝天,雖然我再做的時候有些地方實在無法忍受,給改造了。但是也得考慮時間已經風險,所以要注意要一步一步的蠶食,別大口吃,最後搞不完留一堆碎渣子。路漫漫其修遠兮,哈哈!
結語
項目的此次重構還有許多不完善的地方需要優化,MVC也好MVP也好,關鍵得讓你的工作變的高效,減少無用功。所以,從長遠出發,如果你的項目目前是一堆陳舊的代碼,是時候重構啦。對於一些項目,從MVC到MVP是一種進步,也是重新梳理程序邏輯的一次機會。重構確實要花一些精力,但是如果你不動他,那麼你永遠就是開着拖拉機跟賽跑,累死也不見效。算了,又水了一篇,哈哈,做爲一隻猿,碼碼字也算是本業啦。希望各位大神賜教。