心理學中有一篇相當古老、但又非常重要的**,題為《魔法數字七(上下浮動二):人類資訊處理能力中的一些限制》。這篇文章衡量了大腦處理資訊的極限,並給出了乙個具體的數字:人腦可以同時容納五到九個概念。我們當然能夠把這個有趣的結論延伸到諸多領域當中,但對軟體開發人員而言,下面兩項含義最為重要:
總而言之,這是一場以降低概念描述難度為目標的心理戰,奪取的是珍貴的心理容納空間。
正如英國計算機專家 hoare 所言:軟體設計構建有兩種方法,一是使其盡可能簡單,從而一目了然確定其中不存在缺陷;另一種方法則是使其極為複雜,以至於看不出什麼明顯的缺陷。
遺憾的是,他還補充道:第一種方法其實要困難得多。
在軟體開發當中,新增新的模組、新的類以及越來越多的**是件很簡單的事。這能夠解決軟體需要面對的更多用例,但更大的**量所產出的結果卻越來越少。正如 jamie zawinski 所說:每乙個程式都會不斷擴充套件,一直擴充套件到像人一樣會收郵件、看郵件。而那些無法擴充套件的程式,最終會被能夠擴充套件的程式所取代。
從本質上講,我們一直在不斷擴充套件程式。我們向其中新增更多模組、更多類以及更多**,而且對於每一段**,我們都需要確保其能夠與原有**順暢協作,從而在這個複雜性呈指數增長的過程中繼續保持進一步擴充套件的空間。之所以會這樣作,是因為增量總是更簡單的——至少在起步階段更簡單。
在另一方面,越是簡單的東西開發起來就越困難。這要求開發人員考慮潛在的模式與行為,並消除一切不必要的元素。但最終,這樣的思維方式能夠成就更出色的成果,因為我們只需要使用極少的概念與精力,就可以描述並理解程式,確保大家專注於更多巨集觀目標、而非細枝末節。
實際上,發現這類複雜而臃腫的構造並不困難。我們看看程式手冊就能知道個大概,如果其中有專門的章節來描述結構背景之下的眾多詞彙,基本可以斷定程式複雜度已經失控。
下面來看乙個例子,即 abstract factory(抽象工廠)模式。為了描述其工作原理,我們需要定義很多名稱:
之所以存在這麼多名稱與圖類,是因為複雜性比簡單性更易於實現。這也迫使程式設計師採用針對性過強的物件建立方式,而無法選擇復用儲存在某處的物件等其它可能的解決方案。通過以下方式,我們嘗試降低其整體複雜性:
現在,該模式只關注能夠返回 producta 或者 productb 例項的物件。它可以對該類進行例項化、從資料結構中獲取預先構建的物件,或者從某處提取該物件——具體方法無窮無盡,但這些都不重要;真正重要的是我們的目標:開始時沒有物件,結束時有了物件。現在再來看名稱列表,兩項操作:
這樣,我們可以自由地將該操作放在某個類、某個結構或者是某個指標當中。在使用時,我們只需要配合必要的引數對該操作進行呼叫,它就會為我們提供相應的物件。
在設定中,我們可以將第一項操作設定為任何能夠生成 producta 的形式,並將第二項操作設定為任何能夠生成 productb 的形式。沒有類圖、沒有序列圖、沒有額外的類、沒有不必要的字,也沒有歧義——因為我們能夠對某項操作做的只有呼叫,將其作為引數進行傳遞,獲取返回結果並加以儲存。畢竟函式與操作在本質上就是帶有引數的值。我們要如何利用介面 producta 獲取某個物件?如何才能返回乙個 producta?答案很簡單:使用第一項操作。
我們已經在 abstract factory 的修正版中描述了擁有良好構造的抽象結構。
構造良好的抽象
abstractfactory 模式顯然不是什麼好抽象,因為它包含一切開發者不關心、也沒必要關心的繁瑣細節——例如屬於抽象、必須建立物件,以及使用 new 關鍵字等。作為使用者,我並不關心這麼多細節,但這些細節就在眼前,想躲都躲不開。
相反,我只希望擁有「一項能夠利用 producta 介面為獲取物件的操作。」我只需要進行呼叫,它就能返回 producta 的結果。至於具體獲取方式,我不知道、也不在乎。
abstractfactory 模式不是什麼好抽象,因為它沒有得到良好組合。看看它用到的兩種方法:其一是建立 producta;其二是建立 productb。為什麼要把它們放在同乙個 factory 當中?為什麼不能把這兩項操作分開,並讓希望將二者一同使用的使用者將其放進同乙個元組中?a 和 b 在同乙個類中,絕對不是什麼良好的構造方式。我該如何組合?如果其它地方也有需要使用 producta 的操作怎麼辦?那項操作是否需要了解 abstractfactory 中的錯誤鏈?
abstractfactory myfactory = new factory1();
producta myproduct = myfactory.createproducta();
abstractfactory somethingdifferent = new somethingdifferentfactory();
somethingdifferent result = somethingdifferent.fabricate(myproduct);
return result
相反,如果擁有「一項能夠利用介面 producta 為我獲取物件的操作」,而另有一項操作要求使用 producta 以構造別的結果,那就可以呼叫第一項操作來獲取 producta,然後再用它來執行第二項操作。在型別方面:
operation : () -> producta
otheroperation: producta -> somethingdifferent
因此: otheroperation(operation())。完事,就這麼簡單。
廣州品牌設計公司
遺憾的是,很難通過語義檢測組合性是否良好,因為開發人員已經習慣了那些沒有組合性可言的做法,因此很多人壓根不知道所謂組合良好究竟是什麼概念。好的組合其實能夠輕鬆感受到,這有點像是樂高積木,每一塊都能輕鬆與其它塊匹配起來,共同搭建出規模可觀的作品。
這塊有個三角形尖頭,我們看看哪些積木塊有三角形開孔。
當具有良好的組合性時,我們不需要使用介面卡(或者不會設定介面卡這樣的概念,因為連線機制本身非常簡單)。當具有良好的組合性時,我們只需要將各部分連線起來即可構建成乙個整體,而不必擔心這些部分會以意想不到的方式相互作用。
其整體,就是各部分相加得出的精確總和,僅此而已。
我們已經看到了 abstractfactory 如何破壞「獲取 producta」這樣乙個簡單的概念:乙個 factory 即為乙個 abstract,其通過 createproducta 方法利用 new 以 < > 乙個擁有 producta< > 的 producta1。
這裡單是關鍵字與概念就多達 10 個,超出了最聰明的大腦所能輕鬆處理的極限。更糟糕的是,由於太過刻板,我們只能使用這項操作建立物件、而無法復用物件。這也是程式設計為何如此困難的原因之一:我們毫無意義地抬高了它的難度。
程式設計師應知 簡單就是美
我們經常會聽到這樣一句話 簡單就是美,或者是這句話的各種變體,而且這句話不限於行業,不僅僅是在軟體業,在各種涉及到設計藝術的領域,很多大師級的任務都會告訴我們,簡單就是美。在這裡我當然只想針對軟體開發相關的內容來談,其實我們要解決的問題就是 到底要多簡單呢?對於ui設計 不需培訓直接能使用 還記得曾...
程式設計師應知 簡單就是美
我們經常會聽到這樣一句話 簡單就是美,或者是這句話的各種變體,而且這句話不限於行業,不僅僅是在軟體業,在各種涉及到設計藝術的領域,很多大師級的任務都會告訴我們,簡單就是美。在這裡我當然只想針對軟體開發相關的內容來談,其實我們要解決的問題就是 到底要多簡單呢?對於ui設計 不需培訓直接能使用 還記得曾...
程式設計師應知 簡單就是美
我們經常會聽到這樣一句話 簡單就是美,或者是這句話的各種變體,而且這句話不限於行業,不僅僅是在軟體業,在各種涉及到設計藝術的領域,很多大師級的任務都會告訴我們,簡單就是美。在這裡我當然只想針對軟體開發相關的內容來談,其實我們要解決的問題就是 到底要多簡單呢?對於ui設計 不需培訓直接能使用 還記得曾...