面嚮對象語言三大特徵和“邊界"

       人類解決複雜問題的重要辦法之一就是“分解”,那麼依據什麼去分解?這裏必須提到一個概念:邊界。我們迴歸軟件架構設計,清晰的邊界是一個系統是否足夠優秀的首要標準,我們常說“高內聚,低耦合”實際上也是在強調一個邊界問題。如果沒有邊界,我們怎麼能知道哪些功能、類、函數應該劃歸到一起?如果沒有邊界,怎麼來談兩個模塊、類之間的耦合度關係是高還是低呢?

       倘若系統、模塊、類的邊界不夠合理和清晰,可能會不斷被外來需求變化干擾,系統就會無節制地變化,系統的架構的穩定性根本無從談起。當然了,邊界是由人來定的,因此邊界的合理性是由邊界切分者的分析設計能力、知識經驗等主觀因素決定的,而且這些方面需要長期的實踐總結,不可能一蹴而就。那麼邊界的劃分有沒有什麼技巧性呢?

       最簡單的辦法就是從“關鍵核心問題和需求”的維度進行切分。實例一:我們場地系統的門禁卡管理系統要求可以支持多家廠商,這就需要把具體廠商的對接邏輯切分出去,而管理系統不用關心具體是哪家廠商,因此這裏需要抽取一個通用接口組件、和一堆具體廠商對接邏輯組件,以後客戶需要採購需哪家廠商,我們就把相應的對接邏輯組件扔到運行環境中即可。實例二:競價系統中有一個競價狀態監控和設置的功能模塊,這個模塊的功能是通過定時器將符合結束條件的競價會狀態設置爲結束。經過分析發現,這個模塊和競價模塊關注的問題不同,競價模塊一個非功能性需求是“高併發”,因此需要集羣支撐,而這個競價狀態監控和設置模塊只要有一個實例運行即可,沒有“高併發”的要求,如果和競價系統放在一起甚至會引起多個實例爭用資源的問題。因此,我們需要把這個競價狀態監控和設置的模塊切分出去,單獨部署一份實例即可。實例三:同樣是競價系統,有這樣一個重要需求,如果萬一競價過程中發生異常,比如被黑客DDOS攻擊,競價管理員可以隨時暫停競價過程。倘若把管理員的“暫停功能”和競價系統部署在一起,則在面臨DDOS攻擊的時候,管理員自己也無法登錄系統,況且管理員的管理功能對併發量要求很低,對安全性要求很高。於是我們可以把管理員的功能切成一個單獨的子系統,單獨部署到一臺內網機器上,形成一個“綠色通道”。實例四:系統對日誌的API訪問的性能要求很高,而且日誌的數據量極大。這樣我們就可以把這個日誌系統抽取成一個微服務,其他系統調用這個微服務即可。微服務天然的性能橫向擴展能力可以化解性能問題,同時微服務的隔離特性可以讓我們有針對性地去選擇具體的技術,基於日誌數據的特點,我們可以選擇非關係型數據庫,比如採用Elasticsearch或者是MongDB作爲存儲日誌的數據庫,這兩個非關係數據庫對海量數據的支撐能力剛好可以解決數據量的問題。好了,這種例子很多,就不一一舉例了。

       另外需要注意的是,邊界不應該頻繁變化,有時候也不能一成不變。“固化”和“變化”需要結合系統具體的上下文環境和需求情況辯證去看。如果上下文環境的要求已經發生質變,比如網絡環境發生變化了,當前的架構已經不能滿足了。再比如需求需要支持多種支付方式,而之前是寫死對接支付寶,那麼這個時候就需要調整邊界。需要把具體支付方式單獨切出來,使用類似於策略模式來讓整個架構符合“開閉口原則“。可以採用“兩頂帽子”的辦法來解決這個問題。就是說,先修改架構和代碼使得既支持原來的需求,又可以滿足新的擴展需要,比如符合了“開閉口原則”,然後添加新的需求。實際上架構調整的時機就是這個時候。

       邊界的問題講完了,在這裏我們順便要延伸一個和邊界有關的概念:面向對象的三大特徵。

       面向對象的第一個特性就是:封裝性。我們常常有個錯誤的理解,封裝性就是private關鍵字等,實際上面向對象特徵強調的是架構思想層面的東西,我們如果只是用語法層面的特點去解釋,是有失偏頗的。封裝性最重要的目的是劃清邊界,只有在劃清邊界的基礎上才能談“解耦”。在java語言中封裝性除了private關鍵字外,還體現在接口、抽象類、final關鍵字等等上,甚至OSGI提倡的組件化也是這種思維的延伸。我們要喫準這些概念,但同時要審時度勢去看待問題,不被死概念所束縛,這個恰好就是一個架構師價值的體現,這個價值來自於長年累月的積累。

       使用面嚮對象語言開發的程序,未必真的就是面向對象的。面嚮對象語言,除了它的語言元素和基礎API外,更爲重要的是我們需要用面向對象的設計思想和方法去駕馭這些語言元素和API,否則就變成了開發語言的奴隸,編碼就變成了毫無層次性的API堆砌。我想詹姆斯.高斯林這些軟件大師們他們在實際開發過程中一定是先想到架構,然後再去尋找支持這種架構思路的語言元素,於是他們發現面向過程語言的層次性不夠、編寫的程序邏輯安全性保護能力不夠、邊界清晰性不夠、以函數爲一等公民的方式替換性不夠強。帶着這些問題然後纔有了面向對象的設計思路。然後他們才根據面向對象思想的需要,創造出這套java語言工具。比如說面向過程的語言主要是以函數爲邏輯單元,強調了“空間”上的結構,所以相對扁平,而面向對象的語言不但通過類、接口強化了空間的特性,保證了邊界更加安全,而且加入了“時間”的特性,比如繼承性、多態就是從時間角度去考慮的。所以我們在設計架構的時候一定要有這個意識,只有緊抓“特性”才能把面嚮對象語言用到極致。
        另外,我們學習一門開發語言,如果只關注語法而不關注思想,實際上有點本末倒置,在學會了語法後,我們一定要有意識去掌握這套思想,這個有點屬於“道”層面的東西,具有通用性,不受限於具體的開發語言,當然也是最難掌握的。但是不論如何,我們必須經過長期的練習、實踐,打通設計思想和工具之間的隔閡。一旦解決了這個問題,就相當於打通了任督二脈,甚至可以輕鬆去駕馭其他面向對象的開發語言了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章