抽象的精神

這裏寫圖片描述

軟件設計,一直是一個非常抽象的,非常難懂的領域。
然而設計,並不是科學,雖然有評價標準,卻沒有是非對錯。好的軟件,就像是藝術品,閃耀着前人智慧的結晶。

本文將探討一下流行的軟件設計,以及總結一下好的設計原則和方法。

設計的基本原則

一談到軟件設計,很多人都會講,你要怎麼怎麼設計軟件,怎麼怎麼才能面向對象,怎麼樣才能符合設計模式。沒錯,目前學軟件設計,最初接觸的可能就是面向對象的設計方法,23種設計模式。

但我要說,軟件設計,不是死板的,不是隻有這些模式的。軟件設計,是更爲靈活的藝術品的創作,而面向對象,可能只是其中的一個派系而已

我們所熟悉的面向對象,只是萬千設計方法中的一種,23種設計模式,也只是設計中的冰山一角,我們要跳出面向對象的小圈子,去看看外面的風景。

但無論什麼樣的設計方式和思想,總得有一個評價標準,或者說是一個共識,來解釋什麼樣的設計是一個好的設計,這個基本標準就是:高內聚,低耦合

所謂高內聚,是指一個功能,或一個模塊,內部的封裝性較好,同樣的功能,儘量只存有一份代碼,這樣你在修改一個功能時,往往改動就很小。而且內聚性高的代碼,很注重接口的穩定,在不修改接口的情況,修改內部的實現,對外部影響極小或根本無影響。

低耦合,是在說代碼模塊間的耦合性要低,模塊能較容易的移動和替換,模塊間的耦合性低,最大的好處就是可維護性強,一個模塊出現問題,方便替換。而且複用性強,同一個模塊,可以被多個地方引用,降低了軟件的成本。

舉個栗子

舉個例子

我們現在要做一個在線購物的網站,有用戶和管理員兩種角色,需要維護一個商品列表,用戶的購物車,有什麼樣的設計方式呢?

用例圖

這裏我們只是給出簡單的例子,實際情況往往比這複雜的多。

方法1:

我們給每個頁面寫一段代碼,假設我們用JavaEE實現,那麼我們可能建立了幾個頁面,我們可以按照頁面劃分功能,然後依次實現,要完成的頁面有:

  1. 登錄、註冊頁面
  2. 查看商品列表頁面
  3. 購物車頁面
  4. 後臺登錄頁面
  5. 後臺管理商品列表頁面

我們會用jsp寫一個個頁面內容,然後通過數據庫操作,將對應表中的數據取出來,並格式化到前端頁面上,在接受用戶提交的表單時,我們爲其查詢數據庫,並進行數據檢查與過濾,然後操作對應的數據表。

經過我們苦逼程序員的一致努力,終於實現了全部的功能,網站可以使用了。
但是…客戶忽然發現,他們希望再增加一種vip用戶,讓vip用戶可以存儲更多的個人信息,綁定自己的銀行卡賬戶,這樣他們能爲vip用戶提供更好的服務。

然而,這並不簡單,由於所有的代碼和頁面邏輯都混在一起,雖然也有按照頁面劃分功能,但添加一種新的用戶角色,大部分的頁面都需要改動,工作量很大。

方法2:

我們先思考一下,是什麼造成了改動的困難。如過單獨的考慮一個用戶的模型,也許就能更加簡便的實現,也就是說:我們按照頁面劃分功能模塊,這種思想太粗糙

我們設計一個用戶模型,將單獨的數據操作抽象出來,方便我們擴展用戶類型。通過繼承的方式,我們不但能實現vip用戶,甚至也可以再擴展企業用戶等等。
類圖

我們這裏使用了面向對象的設計方式,由於Java的對象支持非常好,我們這樣設計也是能很方便的用Java類來實現,這樣我們不但可以方便的將模型擴展,更可以簡單的複用模型中的操作。

同理,我們繼續抽象整個項目的結構,像購物車,商品,都可以抽象成單獨的模型類,而關鍵的流程控制,更是可以抽象成控制器。

這種流行的MVC架構到現在,都在軟件架構中發揮着關鍵的作用。
這裏並不想講解MVC架構,而是要說明一個問題,軟件結構直接影響軟件的可維護性,可擴展性

高內聚、低耦合,這些都是良好軟件設計中的基本觀點,但更基本的設計考慮,則是軟件是要分模塊實現的,當然這個模塊是一種對軟件結構的抽象,可以說是類,也可以說是函數,總之是軟件的組成部分。如果一個軟件只有一個函數,所有功能從上到下依次完成,也就沒有了所謂的軟件設計。

軟件設計的核心——抽象

軟件設計的核心,我認爲是對事物的抽象。

軟件設計時,抽象是最基本的方法,來設計出高內聚、低耦合的代碼。希望代碼設計的更好,那麼我們就需要一個好的抽象,一個對現實事物構建的合理的模型

原因也很簡單,軟件的是爲現實世界服務的,只有良好的描述現實事物特徵的模型,才能更好符合我們要讓其完成的功能。

前面例子講解了,什麼是好的抽象,例如將頁面中的實體抽象成數據模型,將實體相關的操作抽象成模型的方法,這直接套用了面向對象的設計模式,形成了很好的抽象。

當然,還有很多種抽象方法,例如在大名鼎鼎的LISP語言中,函數就是第一等公民,將各類方法抽象成函數就是他的做法,甚至是數據的定義,也可以抽象成模型構造函數。這樣就又換了個角度,從另外一個方面來審視整個項目,得出的軟件結構,也大不相同。

在LISP語言中,抽象方式變了,不再那麼關注數據模型,而是關注每一個功能的輸入輸出,將不同的功能組合在一起,形成新的功能,就是函數式編程的基本思想。

好的抽象,往往和軟件是無關的,是在人腦中,將事物的特徵歸類,形成的有效的概念。而一種好的抽象,往往會影響一個時代的設計風格。在Unix系統中,有一個非常棒的設計,將一切抽象爲文件,設備驅動也是文件,IO操作也是文件,系統的監控,也是靠文件。這種設計影響了整個業界,人們驚奇的發現,原來操作系統將一切抽象爲文件後,所有的操作都變得統一和方便了。我們添加新的硬件驅動,不需要修改系統接口,用設備文件的方式就可以訪問,包括進程間通信,也用的是內存共享文件,監控系統參數,只需要打開文件就可以。

編程範式對人思考的影響

我一直說,千萬不要侷限在設計模式中。原因很簡單,固定的設計模式往往會阻礙你對更好的設計的追求。有時會有種一葉障目的感覺。

判斷一款軟件是否設計的較好,最簡單的方式是這樣,先看有沒有冗餘代碼,消除冗餘是代碼優化的第一步。
一般情況,總會有辦法能將冗餘代碼合併在一起。但是不是沒有冗餘就是好的設計了呢?這可不一定。因爲很有可能你雖然消除了冗餘代碼,但引入了複雜的結構,這樣是得不償失的。還有,就是要看可讀性,如果消除冗餘代碼時,降低了代碼的可讀性,本來功能很清楚的一個函數,經過冗餘消除後,反而看不懂是在做什麼了,這時,就要避免代碼整合。
或者說,這時的另外一種方式就是,構建新的抽象方式,抽象新的概念,這樣就能讓思考轉換,構建出既沒有冗餘,又容易理解的代碼。

我很喜歡多範式編程語言,這類語言不規定你具體要使用什麼樣的編程模型,你自由發揮的空間就廣,代表就是C++、LISP、Scala等,都是十分優秀的語言。

如果你只屬性面向對象的設計,那麼我強烈建議你去看一看函數式設計和麪向方面的AOP編程,往往會對你的設計具有啓發式的意義。

分層是解決軟件設計問題的有力方法

其實分層的思想和抽象是一脈相承的,一批軟件功能的整體抽象,往往就能形成一箇中間層,絕大部分複雜問題,都可以通過分層的思想,逐層分而治之,將任務不斷簡化,最後問題得解。

例如我們的互聯網,互聯網就是分層解決問題的典範,在TCP/IP協議下,有對等層的概念。我們知道,TCP/IP協議族採用了4層的層級結構,每一層都呼叫它的下一層所提供的協議來完成自己的需求。
協議分爲:網絡接口層、網絡層、傳輸層、應用層。網絡接口層就解決兩個硬件設備直連的通信的問題,通過出錯重傳機制,保障直連信息的可靠傳輸;網絡層則負責尋找目標地址,分組轉發和路由,將數據填上ip報文段,發送到目標機;傳輸層則複雜格式化信息流,並提供穩定可靠傳輸,爲此,傳輸必須通過三次握手才能開始,而且每個報文包更是要經過接收方發回確認纔算安全傳輸。

如此複雜的互聯網,通過分層的解決方案,得到了可靠有效的實現。現如今互聯網的蓬勃發展,也證明了當年的設計確實是靈活合理的。

軟件設計領域,有這樣一句著名的命題:
任何一個軟件設計的難題,都可以通過增加一箇中間層來實現。

我們這裏不去論證這個命題是否合理,但分層確實是人類這麼多年設計經驗的精華。分層體現了兩個重要的思想,分治和抽象,這是解決問題的關鍵。

本文屬 西風逍遙遊 原創, 轉載請註明出處: 西風世界 http://blog.csdn.net/xfxyy_sxfancy

發佈了84 篇原創文章 · 獲贊 52 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章