今天想查查if...else...和switch相互嵌套怎麼寫,不是通常的嵌套,就是if...的大括號嵌入case分支(其中if自己在switch以外)、交錯起來那種。關鍵字把我引上了很久沒來過的博客園,進入了某個技術很不錯的老夥計的博客。javascript
呃,結果我不但沒找到想要的東西,又看到了if...else...或switch如何如何很差,應該進行面向對象封裝和重構的文章。簡而言之,就是switch的case塊中含有了不少分枝的if...else..。做者毫無例外地給重構爲了工廠模式,先case某種狀況,而後用工廠返回一個command執行(多說一句該做者的例子是javascript,要是過去的我會用高階函數而不是面向對象方法)。我想說的是,通常狀況下把case裏面直接換成一個最普通的函數調用不行嘛....java
固然,若是真的會面對可控的變化,很顯然封裝能夠幫助咱們再從此面對它們時更輕鬆的處理。但拿這樣一個例子來*通常性的*吐槽分支語句們,等於說由於坦克能開炮而汽車不能,因此咱們都應該去買坦克。linux
不管封裝出來的多態也好仍是「硬編碼」的分支也好,這些形態其核心在於存在前提和後續之間一一對應的關係;可是不是全部一一對應的關係,都應該使用某種高大上的方式實現呢?很多人都知道把程序邏輯「數據化」變爲可配置的東西,但什麼叫作「硬編碼」?程序員
代碼即數據。這不是不少高級人士廣泛在講的代碼和數據是一回事、是一個問題的兩種表達,而是說代碼自己就是數據。用戶操做的數據被咱們的程序吃掉;吃進中高級語言這個數據的是編譯器;吃進二進制機器碼這個數據的是CPU及其配套的執行機制。不管是CPU、編譯器仍是咱們本身的程序,當它處理的數據一旦黑紙白字的寫在那裏,就成爲了硬編碼,並不由於這數據是XML或者機器碼而有任何不一樣;區別只是咱們會在項目生命週期的哪一個階段對這些「硬編碼」進行改動?顯然在外圍改動的能力須要內部提供更多的支持,這是須要成本的。數據庫
因此考慮這個問題的時候,關鍵在於需求:咱們須要在什麼場景下變化?在將會部署的目標環境中,要求運行時改變程序行爲,咱們確定要多態+裝載器+用戶界面;不容許從新編譯、或者從新編譯的代價太高,咱們就使用多態+配置文件;有些部分的程序代碼能夠從新編譯、或者做爲動態語言且客觀容許在目標環境中修改,那麼咱們也許只是獨立出一個配置模塊,由於這種方式成本最低且最靈活;產品能夠直接在目標環境中不斷迭代且沒有什麼因素讓修改代碼成本太高,那咱們也許根本不用費那個心思,不少互聯網公司發佈新版本就是這種狀況。異步
歸根結底,進行配置和寫程序代碼,都是提供一種對任務的描述;這沒有什麼本質區別,除了後者有編譯器給你把關避免一些低級錯誤。澄清了這個事實就能夠把精力集中在剩下的方面:在沒有什麼特別需求或限制的時候,程序設計和實現的關鍵在於可讀性。函數
做者的博客裏明確地說道,重構的目的是「將複雜邏輯運算打散並分佈到不一樣的類裏面」;最讓我擔憂的,是文章後面的留言你們裏也傾向於該做者的思路是正確的。關於可讀性,上述文章的做者也提到了:他還說else是排除了全部其它分支的條件大雜燴因此「難以閱讀和管理」。工具
這種說法更像是欲加之罪何患無辭:當咱們用面向對象手法使用默認策略對象時,這個默認策略不也排除了其它針對性策略的前提條件了嗎?那麼憑什麼封裝了以後就好懂,不封裝就很差懂呢?從根本上講,若是一堆if...else...的代碼中若不包含無效的廢話,那麼咱們是不可能消除它們背後的內涵的;重構僅僅是把分支換個地方或者換個形式;在程序在知足需求和限制的基礎上,問題是什麼樣子閱讀門檻最低?佈局
現在每一個程序員都被告知面向對象的可讀性高,但這種聲明是極其可疑的。我過去參與內核移植的工做時,讀了很多linux代碼;弄Android中間層時,又讀了很多中間件的代碼。能夠說Linux代碼大部分都很是易懂,而那些到處封裝的中間件代碼,有些不掛着調試器走一遍,就如同進入迷宮通常,根本不知道哪是哪。你覺得該吃飯了,結果對着一個茅坑,這不是什麼新鮮事。編碼
說實話,上述文章的做者做爲一個工做在某個過去並不過重視方法論的領域,在程序設計方面缺少經驗能夠理解。問題是在這種狀況下,他甚至在原文中說出「分支超過兩個」就不該該以「硬編碼」的形式出現,也太武斷了。
若是隻是嫌代碼太亂,那麼把分支以後都改成一個函數調用,天然而然能避免嵌套、縮短行數,讓代碼從「亂花漸欲迷人眼」,變成「淺草才能沒馬蹄」。再進一步把if後面括號中的判斷,放進有明顯意義的函數裏,就變成了和excel表格同樣易懂的東西。在表達一組對應關係的描述中,把全部細節在當前層次隱藏,每一個條目不管在字面意思上仍是排列形態上也同時具備了明確性。
咱們處理的不少邏輯,只有寫在一塊兒才能一目瞭然;現在不少語言提供異步操做關鍵字以免完成時回調的兩段式寫法,就很好地說明了對完整性的需求是普遍存在的,且已經重要到在一些狀況下最好由語言直接提供支持的地步。具體到分支語句則能夠很是好的把一一對應關係展示在眼前:只要A->B的形式沒變,任何其它一樣完整的表格都不會有什麼哪怕表面上的差別,最可能是換幾個不一樣形式所要求的不一樣字符罷了。
在實踐中若不存在運行時改變行爲的需求或沒法從新編譯的限制,保證一一對應的關係每一個佔據一行、可以自我說明且不包含冗餘信息,分支即使再多(好比一萬個)也不會比配置性代碼或者XML文件難懂;而對比拆的七零八落的精巧設計,具備完整性的直接描述顯然更具備優點。
事實上我傾向於,對於比明顯的對應關係更復雜得多的狀況,咱們也無需使用那些臆想中的「讓程序更易讀」的方式把一件事拆成不少片斷以管理每一次的閱讀量。只要咱們沒有運行時改變行爲的需求或者沒法從新編譯的限制,咱們就沒有必要使用多態等面向對象方法並承受它們額外的trade-off,甚至連拆出函數都不用。
像複雜數據的解析,將這部分工做抽取出來以後(可用面向對象或C++模板式的泛化甚至宏實現,仍是看需求和限制),具體的代碼徹底能夠生成。好比能夠用javascript寫一個頁面,直觀的把要處理的單位表示爲方塊,經過圖形界面安排次序,經過form輸入相關信息,而後生成C/C++或任何語言代碼;爲了反向生成圖,還可使用中間文件記錄佈局信息,或直接從生成的代碼獲取信息,仍舊用javascript展現出來。這些並不難,其成果(在這個例子是圖)比代碼直觀得多,並且這樣一個工具它的可複用性也要比各類代碼級別的抽象來的普遍得多。
這裏面關鍵在於,臆想中「更易讀」的方式,只是對正在設計和實現程序的咱們本身而言。當咱們一點一點的分析問題,並絞盡腦汁完成一個「完美」設計的時候,咱們完全的理解了眼前的一切,並讓東西和咱們的思路保持一致,這時候咱們天然以爲本身的做品很易讀。可是由於其它人沒有走過這個思惟路徑,甚至可能一時走不出十分類似的思惟路徑,咱們怎麼能指望他們快速理解、而且能夠嚴格按照做者設定的方式去繼續維護呢?
實踐中,這些Linus所謂的「漂亮的堅固堡壘」也一點很差讀,哪怕對於面向對象重度中毒者也同樣;這些發燒友只會一遍又一遍的揣摩做者的心思,等終於明白了感嘆一聲「真TM精妙」,而徹底不在意他本身被做者折磨的好似滾了五十遍牀單。相似這種自從面向對象培訓業火了之後愈來愈多出現的狀況,只能是Linus所謂的心智包袱之一。過的時間越久,我就越體會Linus說的,「哪怕只爲了把這些人排斥在Linux核心小組以外這樣一個理由,就決不能使用C++」。
相反,if...else...也好switch也好,只要咱們有心把它們安排得漂漂亮亮,它們就會像只有兩個字段(條件,動做)的數據庫那樣簡潔;因爲對應關係獲得明確的展示,它對任何人哪怕程序外行都是可讀的。除此之外,咱們還有好多直觀展示信息的方式,好比上面講的數據解析「網頁」,聽起來彷佛多了一道手續,但寫這樣一個東西絕對不會比直接上方法論神油折騰複雜邏輯更加費時,卻得到了徹底貼合問題的模型及操做工具,可讀性和可維護性成倍提升。
固然,咱們須要封裝時,不可避免的必須封裝。此乃一句廢話,也是真理。那麼什麼時候須要封裝、多態或者任何其它方式方法?最後重複一遍:當需求或者限制明確的指出這一點、而不是咱們自身的心智包袱暗示咱們這麼作的時候。做爲從面向對象走過的人,我深入的知道這種暗示有時會多麼強烈,咱們真正要作的就是暫時拒絕誘惑、緩一緩、再緩一緩。
對了,上面有「可控的」三字加粗換顏色了,那也是一個重點;對於不可控的變化,任何設計都是盲人騎瞎馬,全部的精力投入連個響都聽不到。很久不來,向全部的老夥計問聲好,不知有幾個還在?貌似很多人事業都蒸蒸日上,恭喜了 :)