廣大程序猿同胞,經常會看到“解耦合”,也有很多人,會用這個詞來裝X,但是,實際真正能理解的人,并不多。接下來,帶大家深入淺出的走一遍,如何解耦合。
首先,我們要知道,為什么要解耦合:通常,我們做一個項目,會用到很多基礎功能塊,比如xxx通信協議,xxxView等等,我們會把這種功能塊封裝成一個庫,如果這個庫,只能在這個指定的項目運行,這就叫高耦合,這就導致了,如果下次再次遇到一個類似的項目,需要用到同樣功能的功能塊時,你會要做很多重復工作。假設,每次使用json時,你都要對json庫進行改造,那將會是一個晴天霹靂。
但是,事與愿違,有些情況,還真的不太好解耦。
這里,我們先舉個栗子,比如排序。
一個排序功能,對于大部分比較初級的程序猿來說,可能會寫成這樣:
sort(List<Integer> list)
這樣就導致了一個問題所在,這個方法只能排序int型數據,如果下一個項目,需要用到對String進行排序,那就很尷尬,感覺明明要成功了,但是又差一點。對,就是差這一點,就是代碼解耦的關鍵。
我們先要明確,我們需要做的是排序功能,在這個過程中,我們不可避免的需要使用2個數據的大小對比,而這個數據,可能是任何數據,也就是說,排序算法,我們是可以確定下來,做成不動的庫,但是有一個數據大小匹配是我們無法做到的,或者說是庫的耦合點,那怎么辦呢?
我們就讓使用我們這個功能塊的人,告訴我們就行啦。
下面,我們參考Android庫里面,有個排序的api
Collections.sort(List<T> list, Comparator<? super T> c);
這里,Comparator這個接口,就是使用者,需要實現,并且傳遞進去的接口。這樣做,這個排序功能塊就可以應用在任何場合,達到一次開發,受用終身的目的。是不是很神奇?
我們再舉個栗子,socket
我們在開發時,經常會用到socket庫,而socket最常用,最常用的一個功能就是:“連接->發送數據->接收數據->斷開連接->回調結果”
所以,如果需要把這個流程,封裝成一個功能塊是很有意義的。
但是,這里有一個問題,是阻礙封裝的,就是 “接收數據->斷開連接”,socket讀取數據時,是一個inputStream,是個流,也就是說,其實,你并不知道,數據怎么樣才算接收 完整/完畢
可能,有的協議,是通過頭2個字節來判斷整個數據長度可能,有的協議是有幀頭,幀尾,轉義符來判斷整個數據長度……
這讓我們很頭疼,那怎么 解決了,既然無法知道的東西,就讓應用程序來告訴你唄。和上面一樣,傳入一個協議實現唄:
public interface UnZipDataAction{// 返回null,表示未接收完全,繼續接收,返回完整的byte[]就認為是已經接收完畢,把結果返回給應用,并且斷開連接byte[] getRealData(byte[] recvData); ErrorCode getErrorCode(); }
這樣,我們就把“連接->發送數據->接收數據->斷開連接->回調結果”整個流程封裝成了通用的功能塊了。
解耦總結來說就是:你能知道的東西就寫死,不知道但是又必須知道的東西,就讓應用程序來告訴你,在java里面叫接口,在有些語言(OC, swift, C/C++)里面叫做代碼段。