前言
最近在看同事們在分享 OOP(Object-oriented programming) 的觀念,在過程中他特別提到了抽象
也是我今天寫這篇的原因,在過程中我假設了一種情境來討論物件應該怎麼切分比較好
這裡要說明,這個討論的過程中的程式語言是以 Dotnet 來說明的,因此有些地方並不一定是用在每種語言上
專有名詞
耦合(Coupling)
在我的認知裡面,耦合是指物件跟物件之間的關係,若高耦合的話,很高機會改了其中一個物件
導致另外一個物件故障
也就是業界常說的改 A 壞 B
抽象類別(Abstract Class)
特性
- 不可以直接透過 New 來建立物件
- 可以訂定抽象方法,強迫繼承的物件去實驗方法
- 可以寫共用方法的邏輯在抽象類別層
介面(Interface)
特性
- 不可以實作,僅僅只是是規範而已
- 繼承的Class必須要實現規範才可當作成此介面
C#9.0打破了這個特性,但我不太能接受就是了
情境
有一個班級,裡面有學生和老師
我們要定義出班級裡面的學生和老師
學生和老師都有開始工作(上課)、結束工作(下課)
並且由班級來決定是否開始工作(上課)
物件切分
依據情境來看,我們可以切出有三個主要物件
- 班級
- 學生
- 老師
由上方可見班級對老師、學生來說是耦合的,很高機會改動了學生這個物件,會連帶影響到班級
最後面再來解決物件耦合的問題
第一次抽象
基於老師與學生都是人的情況下,我們可以抽出一個抽象類別叫做 People
並在 People 裡面定義開始工作與結束工作的抽象方法,待繼承的人實作
好處
若未來有共用的方法要實作我只要修改 People 即可
壞處
根據前面的類別圖可以看到 People 和 Class 仍是高耦合的情況
People、Student、Teacher 本身就是同類,因此不算是耦合
第二次抽象(解耦合)
這邊解耦合的方法會採用 Interface 的方式來進行解耦合
Class 與 People 的相依變成了一個抽象的 Interface ,後續不管 People 底下的類別怎麼變更,只要符合 Worker 的規範,就都不會影響到 Class 導致編譯錯誤而綁手綁腳的
而若要做測試,也可以在 Woker 那層建立一個 FakeWoker 就可以透過注入的方式來實現 Mock、Stub 了
結語
透過上述的抽象,可以很明顯看出 Interface 才是可以真正拿出來解耦合的
只要下面實作的類別抽換了,仍然可以工作,反而抽象類別是無法進行抽換的。