由軟體構造引申的OOP與POP的心得體會

何莫道發表於2020-06-09

  在大一初學C語言的時候,所解決的問題都是一些輕量級的簡單問題,當時寫過一個教學管理系統。這個教學管理系統的功能很簡單,思想就是“流水線”:按部就班的實現所有流程。要完成整個教學管理系統,實際上就是完成一些函式,這些函式之間的邏輯組織結構就是人所認知的邏輯結構,要完成一個教學管理系統,首先要實現一些功能:比如 1.錄入學生資訊 2.為每個學生分配課程 3.為每個學生分配老師 4.為每個學生錄入成績 5.進行成績的統計。

  上面這個流程很直觀,而且實現起來也很流暢。我們只需要將這些函式進行實現就行了。但是在實際操作中,這樣POP的程式設計過程可能會遇到一些問題,比如某一年,有一些課程可以改由多名教師上課,學生分配的課程可以進行更改,學生可以進行分數複核等等。但凡要實現這些功能,就需要對原有軟體實現做出極大的改造,甚至是幾乎重寫。

  而眾所周知,現在軟體構造講究“敏捷開發”,什麼是敏捷開發呢?

敏捷開發以使用者的需求進化為核心,採用迭代、循序漸進的方法進行軟體開發。在敏捷開發中,軟體專案在構建初期被切分成多個子專案,各個子專案的成果都經過測試,具備可視、可整合和可執行使用的特徵。換言之,就是把一個大專案分為多個相互聯絡,但也可獨立執行的小專案,並分別完成,在此過程中軟體一直處於可使用狀態。

  如果我們僅僅是為了完成課程作業的話,那我們基本用不到版本的更替迭代,問題是如果我們這樣做,那實際工程只能是一堆“屎山”,程式碼幾乎無法維護。這不禁讓我想到此前的報導,美國的很多銀行系統使用的是幾十年前流行的語言,這種語言現在已經基本沒人用了,而且之前的程式碼沒有現在“敏捷開發”的思想,當時的程式碼組織結構極其笨重,雖然很穩定,但是難以修改。在幾十年後的今天當人們想要加以維護時,發現這件事難以登天,即使開出百萬年薪也找不到合適的人。這個例子也說明了軟體“易於更改性”的重要性,試想一下,如果所有軟體都只追求穩定性而不考慮可更改性,那每隔幾年就要進行“輪子重造”,不斷的造輪子,會讓程式設計師們苦不堪言。

  但是通過OOP的思想,我們就可以解決遠古的不具有“物件導向”特性語言的種種缺點。OOP和POP的本質區別在於:他們考慮的事情不同。

  POP是程式導向的程式設計思想,這種思想是“以過程為本”的,類似於狀態轉移。我們要做一件事,首先要考慮的是要實現哪些步驟,就像上面的教學管理系統,每個步驟只有在上一個步驟完成之後才能進行實現。這是一個“流式”程式設計的概念,他模仿人們做事的流程,因此單元與單元之間的耦合度很高,只要有一個功能發生變化,可能就會導致其他的功能完全需要重構。

  而OOP則是物件導向的程式設計思想,這種思想是“以人為本”的,我們將實現每個功能都劃歸給一些特定的物件,比如上面的教學管理系統,我們需要實現的物件可能包括:課程,教師資源,選課系統等等,我們考慮的不是事件與事件之間的耦合關係,我們恰恰是要減少模組之間的關聯關係。這也是為了我們進行後期維護而進行的設計,倘若模組之前耦合度極高,那又會陷入程式導向程式設計的深坑。

  在引入OOP之後,我們就自然而然的可以感受到OOP的三大特徵:封裝性、繼承性和多型性。所謂封裝性,就是模組與模組之間是互不關聯的,也就是他們之間的耦合度比較低,我們可以把模組當做磚頭,實現一個軟體就是完成一些磚塊的堆積。通過封裝讓開發app就像蓋房子一樣簡單,我們不需要自己造各種磚頭,甚至可以複用別人的磚頭。

  所謂繼承性,也是為了簡化程式設計的複雜度,因為自然界有很多的子類和父類的關係,或者說有些物品的所有特徵都存在於別的物品中。那我們只需要通過簡單的繼承,就可以使這些子類完全獲得父類可見的成員變數和方法,大大減低了程式碼量。

  說到這裡,就不得不提一下Java特殊的繼承機制,在C++裡面是可以有多繼承的,即一個子類可以繼承多個父類。但是這樣的設計往往會導致程式碼邏輯之間很混亂。在Java中取消了多繼承的功能,我們一般採用介面的多實現來完成C++裡面需要多繼承才能實現的功能。就像在我們HIT軟體構造課程所寫的三個app中,對於每個app都可以設定不同的介面組合,我們通過實現多個介面來完成這些功能的組合,顯得尤為方便。

  最後就是多型性,這個特性存在的原因就是繼承,比如方法的多型-重寫,子型別多型-通過不同的例項化。

  上面就是一些OOP和POP的功能對比,較詳細的介紹了一些OOP的優點。

 

相關文章