程式設計必須依賴於抽象 ,
抽象又是什麼,對於非本科的來說,課堂中我們只學過程式語言的撰寫,
沒有任何對於程式設計的概念課程,幸好有許多的書與線上課程可以看,
一邊學、一邊實作練習抽象的能力。
在學期間曾經完整地把VB、C++的程式語言入門書籍看完,
但這類的入門書籍都著重在語法的使用,對於抽象概念不會提到,
近期在看的大話設計模式用了附錄把這部分說得很清楚,滿令人驚喜的一個章節,
很推薦看一看,看完之後就想記錄一下"當下"對於抽象的想法。
[以下見解不一定正確,提供參考]
抽象是什麼?
回到主題,許多設計概念的書籍與大神都會提倡,
程式設計必須設計在抽象層面上,類別之間的溝通必須依賴於抽象,
那這個抽象層面是什麼呢?是 abstract 抽象類別嗎? 還是沒有實體的 Interface 介面呢?
我的認知是,兩者都是抽象的實現,但應用時機不同。
先談談抽象,舉幾個例子:
現在有直升機、客機、貨機,他們的抽象概念是什麼? 我會回答:飛行器。
現在有計程車、巴士、貨車,他們的抽象概念是什麼?我會回答:車。
現在有快艇、漁船、渡輪,他們的抽象概念是什麼?我會回答:船。
那飛機、車、船三者的抽象概念是什麼?我會回答:交通工具。
這樣有一點概念了嗎?
是否發現一但變成抽象概念,細節的描述就會消失,
而抽象出來的,還是能夠符合被抽取項目的描述。
該如何選擇 abstract 與 interface
既然知道抽象就是找出一個群體中各個物件的共通點,
那麼 interface 與 abstract 似乎都符合這個條件,那實際上該怎麼選擇呢?
除了 interface 與 abstract 本身的規範之外,可以朝幾個面向去思考。
1. 依照開發時間點來分類:
如果程式尚未開始撰寫,但已經知道有許多類別會有共同的功能,
那麼就以 interface 來定義這些大家都會用到的功能,開發時期大家再來實現它。
如果已經開始開發程式了,發現很多地方是共同擁有的功能,
那麼這時候就會將這些功能抽出變成 abstract 類別,並讓大家繼承去實作,
同時也讓子類別更精簡,因為重複的程式碼都被抽到父類別去了。
這時你可能會想說,那麼兩者情境就算互換也不衝突啊?
沒錯,但還有其他我們必須考量的條件。
2. 依照功能性來區分:
如果這個大家都有的功能和使用的類別是比較沒關係的,例如存檔功能,
演算法類別可能會用到,運動控制類別也可能會用到,但演算法與運動控制並不相關,
這時候存檔功能就應該寫成 interface,讓兩者去使用,因為如果寫成 abstract ,
可能會違背介面隔離原則(ISP),因為不同類別可能需要不同的行為,
不應該被強迫繼承一個無關的功能。
也有可能違背單一值則原則(SRP),因為abstract 不應該負責與核心職責無關的功能。
你不想遵循原則也沒差拉,反正程式可以動就好。(?)
3. 繼承只能一個,介面卻可以實作多個:
和上一點很像,繼承來的類別必須要和子類別具有相當直接的關係,
而 interface 卻可以完全不必考慮這一點,只關注在"功能",
你可以想像 interface 就像是"功能標籤",當你想用到什麼功能,就去實作它,
使用者看到你的類別時,只要看到實做了哪些 interface,也能一目了然的知道具備哪些功能。
結論
我自己整理想法之後,一個比較簡單的使用方式可以透過下面這句話去決定:
由上而下開發,使用 interface,由下而上開發,使用 abstract。
這是一個很粗糙的辨別方式,也沒有一定的對或錯,
一切都看開發當下的環境條件去決定,
記得之前上過軟體課程,老師不斷重複提到,
"寫程式是不斷的取捨,找出平衡點,沒有對或錯,以目的為導向。"
假使今天你需要執行速度非常快的程式碼,而程式碼必須寫得很髒才會夠快,
那就寫得很髒吧,達成目的才是你最需要做的事。

沒有留言:
張貼留言