去年10月底換到了新公司,做移動研發(fā)組的負(fù)責(zé)人,剛開始接手android項(xiàng)目時,發(fā)現(xiàn)該項(xiàng)目真的是一團(tuán)糟。首先是其架構(gòu),是按功能模塊進(jìn)行劃分的,本來按模塊劃分也挺好的,可是,他卻分得太細(xì),總共分為了17個模塊,而好幾個模塊也就只有兩三個類而已。但應(yīng)用本身其實(shí)比較簡單,要按功能模塊來分的話,最多五個模塊就夠了。另外,有好多模塊劃分也很模糊,也有很多類按其功能其實(shí)可以屬于多個模塊的,也有些類定義不明確,做了不該做的事。有時候,我要找一個界面的Activity,按照其功能應(yīng)該屬于A模塊的,可是在A模塊里卻找不到,于是,我只好去AndroidManifest文件里找了,找到才發(fā)現(xiàn)原來在B模塊里。也有時候,我要找另一個界面的Activity,可我看遍了所有模塊,也沒看出這個界面應(yīng)該屬于哪個模塊,沒法子,又只能去AndroidManifest文件里找了,找到才發(fā)現(xiàn)竟然在C模塊里。代碼也是又亂又臭,導(dǎo)致出現(xiàn)一大堆bug又不好找,改好一個bug又出現(xiàn)另一個。整個項(xiàng)目從架構(gòu)到代碼都是又臭又亂,開發(fā)人員只是不停地改bug,根本沒法做新功能,更別談擴(kuò)展了。當(dāng)時,公司已經(jīng)有為不同客戶定制化app的需求,而現(xiàn)有的架構(gòu)完全無法滿足這樣的需求。因此,我決定重構(gòu),搭建一個易維護(hù)、易擴(kuò)展、可定制的項(xiàng)目。 我將項(xiàng)目分為了四個層級:模型層、接口層、核心層、界面層。模型層定義了所有的模型;接口層封裝了服務(wù)器提供的API;核心層處理所有業(yè)務(wù)邏輯;界面層就處理界面的展示。幾個層級之間的關(guān)系如下圖所示:
接口層封裝了網(wǎng)絡(luò)底層的API,并提供給核心層調(diào)用。剛開始,為了簡單,該層的核心類我只定義了4個:
PostEngine將請求封裝好發(fā)送到服務(wù)器,并對響應(yīng)結(jié)果的json數(shù)據(jù)轉(zhuǎn)化為Response對象返回。Response其實(shí)就是響應(yīng)結(jié)果的json數(shù)據(jù)實(shí)體類,json數(shù)據(jù)是有固定結(jié)構(gòu)的,分為三類,如下: {"event": "0", "msg": "success"} {"event": "0", "msg": "success", "obj":{...}} {"event": "0", "msg": "success", "objList":[{...}, {...}], "currentPage": 1, "pageSize": 20, "maxCount": 2, "maxPage": 1} event為返回碼,0表示成功,msg則是返回的信息,obj是返回的單個數(shù)據(jù)對象,objList是返回的數(shù)據(jù)對象數(shù)組,currentPage表示當(dāng)前頁,pageSize則表示當(dāng)前頁最多對象數(shù)量,maxCount表示對象數(shù)據(jù)總量,maxPage表示總共有多少頁。根據(jù)此結(jié)構(gòu),Response基本的定義如下: public class Response<T> { private String event; private String msg; private T obj; private T objList; private int currentPage; private int pageSize; private int maxCount; private int maxPage; //getter和setter方法 ... } 每個屬性名稱都要與json數(shù)據(jù)對應(yīng)的名稱相一致,否則無法轉(zhuǎn)化。obj和objList用泛型則可以轉(zhuǎn)化為相應(yīng)的具體對象了。 Api接口類定義了所有的接口方法,方法定義類似如下: public Response<Void> login(String loginName, String password); public Response<VersionInfo> getLastVersion(); public Response<List<Coupon>> listNewCoupon(int currentPage, int pageSize); ApiImpl則實(shí)現(xiàn)所有Api接口了,實(shí)現(xiàn)代碼類似如下: @Override public Response<Void> login(String loginName, String password) { try { String method = Api.LOGIN; List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("loginName", loginName)); params.add(new BasicNameValuePair("password", EncryptUtil.makeMD5(password))); TypeToken<Response<Void>> typeToken = new TypeToken<Response<Void>>(){}; return postEngine.specialHandle(method, params, typeToken); } catch (Exception e) { //異常處理 } } 實(shí)現(xiàn)中將請求參數(shù)和返回的類型定義好,調(diào)用PostEngine對象進(jìn)行處理。
核心層介于接口層和界面層之間,主要處理業(yè)務(wù)邏輯,集中做數(shù)據(jù)處理。向上,給界面層提供數(shù)據(jù)處理的接口,稱為Action;向下,調(diào)用接口層向服務(wù)器請求數(shù)據(jù)。向上的Action中定義的方法類似如下: public void getCustomer(String loginName, CallbackListener<Customer> callbackListener); 這是一個獲取用戶信息的方法,因?yàn)樾枰蚪涌趯诱埱蠓?wù)器Api數(shù)據(jù),所以添加了callback監(jiān)聽器,在callback里對返回的數(shù)據(jù)結(jié)果進(jìn)行操作。CallbackListener就定義了一個成功和一個失敗的方法,代碼如下: public interface CallbackListener<T> { /** * 請求的響應(yīng)結(jié)果為成功時調(diào)用 * @param data 返回的數(shù)據(jù) */ public void onSuccess(T data); /** * 請求的響應(yīng)結(jié)果為失敗時調(diào)用 * @param errorEvent 錯誤碼 * @param message 錯誤信息 */ public void onFailure(String errorEvent, String message); } 接口的實(shí)現(xiàn)基本分為兩步:
需要注意的是,Action是面向界面的,界面上的數(shù)據(jù)可能需要根據(jù)不同情況調(diào)用不同的Api。
界面層處于最上層,其核心就是負(fù)責(zé)界面的展示。
模型層橫跨所有層級,封裝了所有數(shù)據(jù)實(shí)體類,基本上也是跟json的obj數(shù)據(jù)一致的,在接口層會將obj轉(zhuǎn)化為相應(yīng)的實(shí)體類,再通過Action傳到界面層。另外,模型層還定義了一些常量,比如用戶狀態(tài)、支付狀態(tài)等。在Api里返回的是用1、2、3這樣定義的,而我則用枚舉類定義了這些狀態(tài)。用枚舉類定義,就可以避免了邊界的檢查,同時也更明了,誰會記得那么多1、2、3都代表什么狀態(tài)呢。然而用枚舉類定義的話,就必須能將1、2、3轉(zhuǎn)化為相應(yīng)的枚舉常量。這里,我提供兩種實(shí)現(xiàn)方式:
public enum BooleanType { @SerializedName("0") FALSE, @SerializedName("1") TRUE }
public enum BooleanType { FALSE("0"), TRUE("1"); private String value; BooleanType(String value) { this.value = value; } public String getValue() { return value; } } 通過gson的方式,直接訪問TRUE或FALSE就會自動序列化為1或0;如果通過第二種方式,因?yàn)闆]有序列化,則需要通過getValue方式獲取1或0。 結(jié)束以上就是最基本的架構(gòu)了,講得比較簡單,只列了幾個核心的東西。并沒有進(jìn)一步去擴(kuò)展,擴(kuò)展是下一步的事情了,后續(xù)的文章里會慢慢展開。 |
|