2021年8月3日 星期二

[C++ / C#] 抽象是什麼? interface 與 abstract 怎麼用?

程式設計必須依賴於抽象 ,

抽象又是什麼,對於非本科的來說,課堂中我們只學過程式語言的撰寫,

沒有任何對於程式設計的概念課程,幸好有許多的書與線上課程可以看,

一邊學、一邊實作練習抽象的能力。

在學期間曾經完整地把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。

這是一個很粗糙的辨別方式,也沒有一定的對或錯,

一切都看開發當下的環境條件去決定,

記得之前上過軟體課程,老師不斷重複提到,

"寫程式是不斷的取捨,找出平衡點,沒有對或錯,以目的為導向。"

假使今天你需要執行速度非常快的程式碼,而程式碼必須寫得很髒才會夠快,

那就寫得很髒吧,達成目的才是你最需要做的事。

沒有留言:

張貼留言

社會新鮮人如何投資?

我的觀點是,在 沒有很多 本錢 的情況下, 別寄望每個月幾千元放到股票或者最近很夯的高股息ETF就能讓你致富, 先投資自己,讓自己的本業收入提高吧。