企業(yè)級軟件開發(fā)架構(gòu)心得
發(fā)布者: 鄭州軟件開發(fā) 07-24
什么是架構(gòu)
軟件架構(gòu)絕對不只是框架的堆砌,在我看來,架構(gòu)是為了方便軟件維護、擴展、安全性、切入性(我也不知道有沒有人提出過這個關(guān)鍵字,因為的確很少看見,簡單來說:我這里說的切入性就是指一個以前沒有接觸過這個項目的人,能快速加入到這個項目中,對項目進行維護、修改和擴展)
維護性
一個好的軟件(不一定是成功的軟件,這里說的好只是程序員認為的代碼方面)肯定是能方便維護的,出了問題能快速定位,需要修改時能快速修改,并且在一定程度上不會說一修改就一堆bug,這就是我認為的可維護性,當然后面要說到的切入性其實也算是維護性,不過為什么單獨放出來在切入性時我會詳細說明。至于怎么樣才能使一個軟件維護方便,我覺得有以下幾點:
1.代碼規(guī)范
一份代碼如果沒有遵循任何規(guī)范,那么我相信它的可維護性是很差的,就算是你一個人做出來的,估計過了幾個月去修改的時候也會冒出一句這TM是什么鬼
2.框架穩(wěn)定性
很多時候很多開源框架剛出來的時候,也許功能十分強大,但是畢竟剛出來,沒有經(jīng)過充分的測試,所以還是會或多或少存在一個不穩(wěn)定因子,所以建議在選擇框架時盡量選擇成熟穩(wěn)定的框架,哪怕功能和性能的確比不上剛出來的框架。當然這也不是說完全不用剛出來的框架,畢竟都不用,那么它也永遠成熟不了,至于到底用不用和怎么用,本文的框架選擇和使用篇也會詳細分析說明
3.封裝
本來想說AOP的,但是個人覺得很多專業(yè)性的名詞也比不上一些通俗的形容,畢竟本文主要的目的是讓人理解,不是提出理論。封裝這個在Android中是經(jīng)常使用的,簡單來說就是把一些常用的、通用的東西進行一個封裝,通過統(tǒng)一入口進行調(diào)用,這樣出問題就只需要修改一個地方,就能全部修改過來。同時封裝也要注意一些常見的坑,比如我曾經(jīng)就踩過的context坑,當時封裝了一個UIUtils(主要是針對UI相關(guān)的工具類),因為很多方法都要使用context,所以直接application傳進去,保存了,所有方法都不用傳context,但是這樣卻出了一個bug,那就是有些操作用application的context是有問題的。當然這種還比較好處理,但是如果因為封裝導致內(nèi)存泄露,這就難以查找了,比如你傳入了一個activity的context,但是activity已經(jīng)關(guān)閉了,但是因為你封裝的方法里面還在繼續(xù)使用這個context,所以activity的內(nèi)存也是不會釋放的,所以封裝的時候也一定要注意,不要給自己挖坑
4.耦合
針對耦合這個東西相信很多文章都說過了,如何解耦合,不過個人感覺解耦合這個東西也要適度,不要因為解決一點耦合,花了大量的代碼,浪費了大量的性能,所以解耦合這個東西就一定要把握這個度,過度設計是有問題的設計,這點我是贊同的。同時很多時候封裝會導致一些耦合的問題,比如我曾經(jīng)一個項目中就有個這個一個情況:
因為項目中使用了滑動選取身高的WheelView,因為當時是彈Dialog出來選擇的,所以當時想也沒想就直接封裝了一個Dialog,后面又出來了一個選取年齡的,然后又封裝了一個Dialog,以至于到后面封裝的Dialog有7,8個了,但是有些界面因為選中后的處理有些不一樣,導致Dialog里面的代碼混亂,所以后面就直接簡單的封裝了一個Dialog,傳入需要選中的數(shù)據(jù)集合和選中監(jiān)聽,這樣就用了一個Dialog就能處理多種數(shù)據(jù)的選擇,還能根據(jù)不同界面分別處理,當然這樣也不是萬金油,畢竟這樣每個界面都需要自己實現(xiàn)監(jiān)聽,所以很多時候有利就有弊,至于具體怎么取舍,就看利是否大于弊
擴展性
擴展性簡單來說就是當程序需要新的功能時,能否對其進行擴展以及擴展的難度來判斷,如何提高擴展性,我覺得有以下幾點:
1.抽象接口
這點相信大家都經(jīng)常遇到,比如Android的點擊事件,你想要實現(xiàn)什么樣的點擊效果,自己實現(xiàn)一個點擊監(jiān)聽,然后設置給控件就可以了
2.元素重用
很多時候,很多功能模塊可能使用到相同或者類似的元素,如Android中的一些布局,這些如果抽取出公共部分在進行擴展的時候方便對其快速擴展,當然這個是項目一開始并不能預見的,所以需要在開發(fā)中不斷的去重構(gòu)
3.單一職責
這個其實就是面向?qū)ο蟮膯我宦氊煟热缜懊嫣岬降腄ialog,一開始只有選擇身高的功能,看起來是單一職責,但是其實相關(guān)處理也包含在其中,所以那個Dialog類本身職責已經(jīng)不單純,當然如果一直只有這一個,這樣做沒有任何問題,也能看做單一職責,但是如果有多個選擇和處理的時候,就必須對其重構(gòu)了
4.替換性
替換性包含里氏代換但是也不僅僅是里氏代換,比如常見的Android布局不同,但是其顯示內(nèi)容大致相同,這樣寫布局的時候就可以對相同內(nèi)容的控件指定相同的id,這樣就算替換布局,也不用重寫ViewHolder,當然對于Adapter也僅僅只需要替換相應的布局就ok
5.耦合
這個和維護的耦合相同,畢竟很多地方本來就存在交叉,所以就沒有必要再說了
安全性
個人覺得數(shù)據(jù)安全性并不僅僅是數(shù)據(jù)安全,還有程序的一些操作安全性(簡單來說就是避免程序出現(xiàn)一些非崩潰性異常)
1.數(shù)據(jù)安全性
數(shù)據(jù)安全就包括數(shù)據(jù)抓取、數(shù)據(jù)攔截以及數(shù)據(jù)修改。當然這些并不能完全避免,只能是由我們寫出盡量安全的代碼,比如關(guān)鍵數(shù)據(jù)使用HTTPS以及對數(shù)據(jù)進行md5驗證完整性,對于數(shù)據(jù)修改,可以通過多文件多地址保存文件修改記錄,來確定保存的數(shù)據(jù)是否被修改,畢竟Android只要獲取root權(quán)限,就能對很多文件進行修改了
2.操作安全性
簡單來說經(jīng)常遇到的一個問題,比如按鈕的點擊事件,有可能這個點擊事件是請求網(wǎng)絡或者打開Activity,這樣就會存在事件還未處理完成再次收到事件,只要你一直猛點,肯定可以的,所以這樣就需要我們對控件事件進行一些封裝,比如打開界面的,可以在點擊后禁用按鈕,界面打開完成后才啟用,請求網(wǎng)絡的可以在開始就禁用按鈕,請求結(jié)果反饋了才啟用(不管是請求成功或者失敗)
切入性
切入性就是當另外一個從未接觸過此項目的人,能快速進入這個項目進行開發(fā),當然想要切入性好,前面的維護和擴展是必須要滿足的,下面我就說說我認為能增加切入性的一些點
1.文檔
開發(fā)都不喜歡寫文檔,這是肯定的,但是每當我們?nèi)ソ邮忠粋€項目的時候,發(fā)現(xiàn)沒有文檔估計就要開始罵娘了,所以文檔不僅要寫,還要寫的規(guī)范。我認為開發(fā)中必須要有的幾個文檔:代碼規(guī)范文檔(比如包名規(guī)范,文件命名規(guī)范,id命名規(guī)范等等,具體依據(jù)項目情況而定)、接口文檔
2.注釋
每個類必須要有注釋,方法也要有注釋,同時也要標注好方法最后修改人是誰,這樣出現(xiàn)疑問或者問題別人就知道該去找誰了,當然有些方法是不需要有注釋的,比如重寫父類的方法,只是如果方法內(nèi)邏輯很復雜,可以在方法中添加一些對邏輯的說明。當然注釋也不是越多越好,具體注釋該怎么寫,Google最清楚,不能Google百度也行
3.包名
什么類放什么包簡單,但是一但一個包中的類太多,也是非常不方便,所以正確的分包也是非常重要的,目前常見的Android分包包括針對功能分包(不是指程序功能,而是指UI,http,bean這些功能),還有就是模塊分包(這就是程序的功能了,比如login,user等),當然具體怎么分包需要團隊協(xié)商,防止一個包中類太多,而我現(xiàn)在一個程序很大的情況下,采用的分包是先功能分包,再模塊分包,比如:
wang.raye.demo
|-activity
| |-user
| |-login
|-fragment
| |–user
| |–login
這樣能減少每個包的類數(shù)量,當然如果項目本身并不是很大,可以完全不用這種分包模式,畢竟如果只是小項目,這樣會使項目變得更加難以閱讀
MVC 還是 MVP
現(xiàn)在針對移動端開發(fā),衍生了很多種架構(gòu),如MVC、MVP、MVVP,當然這里著重分析MVC和MVP,畢竟MVVP我也只是了解過一下,沒有詳細接觸,至于什么是MVC和MVP我也不想做過多描述,這類的文章實在太多,這里主要分析一下什么情況下用MVC和MVP
MVC
MVC是以XML布局為V(視圖),Activity或Fragment為C(控制器),數(shù)據(jù)實體為M(模型),但是因為XML的局限性,所以其實我們還是需要在Activity或Fragment中對視圖進行操作,所以這也就是為什么那么多人抵制MVC的原因,因為這也算不上完整的MVC
優(yōu)點:開發(fā)迅速,結(jié)構(gòu)易理解
缺點:當一個界面業(yè)務邏輯一多,不方便維護
MVP
MVP是為XML配合Activity或Fragment為V(視圖),同時抽象出接口,界面相關(guān)業(yè)務抽離出來的P(Presenter)同時通過視圖接口來更新UI,數(shù)據(jù)實體為M(模型)
優(yōu)點:業(yè)務發(fā)生變化時易修改,同時能減少修改過程中引發(fā)bug,也能將多人協(xié)同開發(fā)充分調(diào)用起來(并不是針對一個人負責一個模塊的模式,而是多人協(xié)同開發(fā)一個模塊)
缺點:開發(fā)速度會有所降低
所以對比2種架構(gòu),發(fā)現(xiàn)MVC適合不需要太多業(yè)務邏輯和功能性少的APP,比如數(shù)據(jù)展示類應用,MVP適合每個界面有復雜邏輯以及大型多人開發(fā)的APP
框架選擇及使用 如何選擇框架
1.穩(wěn)定性
如果框架本身就不穩(wěn)定,那么導致的結(jié)果就是程序本身也會漏洞百出,所以選擇框架一定要選擇經(jīng)歷過考驗的穩(wěn)定的框架
2.擴展性
隨著程序功能的增加,以前的框架可能會出現(xiàn)功能不足的情況,但是因為這點是不可預見的,所以我們選擇框架時一定要了解好框架本身的擴展性如何,或者對框架有較深的理解,能夠自己擴展框架,當然有些框架解決的問題比較單一,一般也不用擔心過多的擴展性,比如Butterknife或PreIOC這類單一性框架,但是有些框架經(jīng)常需要配合做一些操作,比如圖片加載框架,常見的一些就是清理圖片緩存、獲取圖片緩存大小、顯示圓角或者圓形圖片, 常用的圖片加載框架UniversalImageLoader都提供了相關(guān)的方法或接口來實現(xiàn)
3.封裝性
封裝性是指能否針對框架進行二次封裝,以及封裝后的耦合度,詳細會在使用篇說明
如何使用
選擇好了框架千萬不要拿來就用,因為再好的框架也有它局限的地方,當然你也可以簡單的在遇到這個框架不能實現(xiàn)的時候,添加另外一種框架,只是這樣項目會越來越大,對于APP來說APK也越來越大,65535 的問題也會提前出現(xiàn),所以為了方便以后有可能出現(xiàn)的切換框架,以及防止初期對框架使用不熟悉而引發(fā)出新的bug,在選擇好了框架后,一定要對框架進行二次封裝,當然有些框架是不需要二次封裝的,比如前面說的單一性的框架Butterknife或PreIOC,但是像UniversalImageLoader、OKHttp等框架,必須要進行二次封裝,至于封裝原則,則是封裝后,調(diào)用框架對于調(diào)用代碼來說是透明的,簡單來說,就是對于框架調(diào)用都通過一個統(tǒng)一的入口進入,并且調(diào)用時,不需要傳入任何跟框架相關(guān)的東西,如果必須要傳入接口,可以通過繼承框架來實現(xiàn)新的接口傳入,這樣在真正的使用框架的地方,沒有任何關(guān)于框架的引用
封裝的好處
之所以要這樣封裝,最大的好處就是一旦框架不能滿足需求時,需要進行框架更換時,只需要換掉框架,同時修改統(tǒng)一入口處的代碼,就能快速的替換整個框架
以上就是我在Android APP架構(gòu)上面的一些心得,此文可能并沒有教你快速搭建一個框架,只是指明搭建框架時需要注意和搭建框架的一個方向,當然軟件是死的人是活的,具體項目具體處理。