#可擴展性
一個好的產品都是不斷修改和重構出來的,如果我們的代碼沒有考慮到可擴展性,會導致修改和重構代碼困難。 做好需求分析和架構設計能提高程序的可擴展性。
##需求分析
在考慮可擴展性需要從需求分析開始,需求分析這步是很多人容易忽視的,有時候需求分析做好了程序就自然有課擴展性。做需求分析是需要對需求進行陳述處理:區分做什么和怎么做,做什么往往不會變,而怎么做是可能會變的,應該把可能會變的部分獨立處理。
比如產品經理告訴我們一個需求:成員列表要按姓名拼音排序(如圖1-26)。
如果我們按產品經理說的做,不做任何分析的話,就可能會把數據庫的排序字段存為拼音。這就沒有沒有可擴展性,如果產品經理以后再告訴你成員列表要把VIP的會員提到前面,這時候你只能痛苦的去修改程序。

圖1-26 成員列表的例子
我們先做需求陳述處理,這個需求是做什么?是做排序, 怎么做? 按姓名拼音。 要知道成員列表要排序這個需求肯定不會變, 但是按姓名拼音的排序方法是可能會變的。我們在做數據庫表設計的時候大家認為排序字段應該是存拼音還是數字?
這個需求主要是要做排序,按拼音只是附加說明,這個附加說明是可能會變的,而排序永遠不會變。既然是做排序,數據庫字段就應該設計為數字類型的,按數字順序排列. 再寫一套算法,將拼音轉換為數字,比如a轉換為1,b專為2 , 新增成員時會將姓名的漢字轉換為拼音,再將拼音轉換為數字,然后存入排序的字段。這樣產品經理告訴你要把某個人提前,只要修改某個人數據庫的排序字段的數字即可,不用修改程序。
做好需求陳述處理,把做什么和怎么做分開,程序就比較有擴展性了,我們還要再寫程序時注意架構設計。
## 架構設計
另外在做程序架構設計的時候我們需要學習很多編程理論,如MVC,OOP,AOP,REST,設計模式等,學習編程理論也要掌握方法,不要濫用編程理論,某個編程理論提出一定是為了解決什么問題,要分析自己的項目有沒有遇到這樣的問題,有這樣的問題采用對應的編程理論,如果沒有這樣的問題硬要用這個編程理論,那就屬于濫用編程理論。
大家可以問問自己是否知道MVC要解決什么問題?OOP要解決什么問題?
還要明白編程理論和編程的基礎知識不一樣, 基礎知識不遵守就是錯誤,比如不按照規定的語法寫程序,那運行程序的時候比如會報錯,而編程理論,不遵守它是不會有錯誤,我們可以靈活的應用編程理論,可以對編程理論做調整來解決自己項目中的實際問題。

圖1-27 編程理論要解決的問題
如圖1-27,我認為很多編程理論都有一個共同的目的“解耦” , 而“解耦”的大專方向是 “正交設計、類要有專職、善于用委托”,按這樣去寫程序,我們無意其中就用上面某些編程理論,、設計模式等。
**什么是正交設計**

圖1-28 不正交的線段
正交的概念來源于數學,如圖1-28第一條線段是斜著的,和垂直的線不不是正交,而另外兩條線段和垂直的線是正交,斜著的那條線段會與多條線都有交點,斜著的線有變動會影響多條線, 如果程序寫成這樣就會出現耦合,如果讓橫著的線和豎著的線都正交, 接觸點會很多,從而減少耦合(如圖1-29)。

圖1-29正交的線段
正交類似于地下黨組織,地下黨會分很多小組,小組內部的人雖然互相認識,但不能讓小組之間有直接聯系。即使某個小組被發現了,在嚴刑拷打也不能獲取小組之外的人員名單。
很多編程理論都符合正交設計,比如OSI七層網絡模型, MVC分層等。

圖1-30 OSI七層網絡模型
如圖1-30所示, 七層網絡模型中,每一層只和上下相鄰兩層有聯系,不能跨層有聯系, 減少層和層之前的接觸點,降低耦合。

圖1-31 MVC分層
如圖1-31,MVC也是一樣的,只是和相鄰的層有聯系, View不能直接調用Model。
MVC,能讓網站風格的修改只固定在V層,而不影響其他層。只要做能讓變化控制在固定的層里,而不影響其他層,那就是一個比較成功的架構。
做架構時要以“控制變化發送在固定的層”為目的,很多人做架構是以“減少代碼工作量”為目的,想做了封裝后只需要很少的代碼就能開發出功能, 如果真的做到了這樣,程序的靈活性反而很低, 不能應對很多需求。
**為什么類要有專職?**
類就是要做區分,把相同的歸為一類,一個類要有專職,它只干一件事情。類封裝得好,我們能說出這個類的職責,比如Db類就是操作數據庫的,Log類就是寫日志的。如果一個類沒有專職,和很多功能都相關,就會有耦合。 我們切忌不要封裝這樣的上帝類,它萬能到什么都能實現。一個類如果很雜,什么都干,沒有明確的職責,那就不能稱其為類,更像是一個雜種。
我們在封裝類的時候,經常發現實際寫的大量的代碼在干和類的職責無關的事情,這時候我們應該把這樣的代碼獨立出來。假如Log類里面有大量代碼不日志無關,和讀寫文件有關, 我們就應該在封裝一個File類來讀寫文件,讓Log類去調用File類,寫日志的方法Log::write。
不直接實現寫日志,而委托File::write來完成。這就是“委托”。在封裝類的時候,多用委托的方式能讓類的職責更加的明確。
**為什么委托優于繼承?**
繼承容易出現組合爆炸的問題。

圖1-32 繼承的組合爆炸
如圖1-32,假設我們有三個類:人、鳥、魚。人類有說話的方法,鳥類有飛的方法,魚類有游的方法。我們如果需要封裝一個類“會飛的人”,它既能說話又能飛, 那么這個類要先先繼承于人類,再復制鳥類的飛的方法到新的類。“會游的人”、“會說話的鳥”等類都有這樣的問題,會復制代碼。功能組合的情況越多,重復代碼就越多,這就是繼承容易產生的“組合爆炸”的問題。
而用委托的方法,能解決組合爆炸的問題。

圖1-33 使用委托解決組合爆炸的問題
如圖1-33,將人類的“說”、鳥類的“飛”、魚類的“游”都委托出去,交給新的類實現。 “會飛的人”不用繼承任何基類,調用“說”和“飛”即可,同理“會說話的鳥”、“會說話的魚”等類也是調用相應的委托類的方法即可。 這樣不用復制代碼即可實現功能的組合,避免組合爆炸。
做到了“正交設計、類要有專職、善于用委托”這一句,程序架構就自然做好了。