go 學習筆記之萬萬沒想到寵物店竟然催生出面向介面程式設計?

snowdreams1006發表於2019-09-28

到底是要貓還是要狗

在上篇文章中,我們編撰了一則簡短的小故事用於講解了什麼是物件導向的繼承特性以及 Go 語言是如何實現這種繼承語義的,這一節我們將繼續探討新的場景,希望能順便講解物件導向的介面概念.

為了照顧到沒有看過上一節文章的讀取,這裡再簡述一下上節文章關於買寵物的故事,如需詳細瞭解,請自行翻閱歷史文章進行檢視.

A: 貓是一種寵物,淘氣可愛會賣萌,看家本領抓老鼠,偶爾還會喵喵喵.
B: 狗是一種寵物,忠實聽話能看家,嗅覺靈敏會破案,一言不合汪汪汪.
C: 我想要買一個寵物,文能賣萌,武可退敵,明個一早給我送來吧!

於是,第二天,A和B各自帶著自己的寵物來拜見C,並附上各自的理由,說的頭頭是道,C總覺得有些哪裡不對,可一時間又無言反駁,只能悻悻收下了貓和狗,白白多花了一份錢!

https://i.iter01.com/images/7742d436468ef3ec7a54cd5fe452376e1a2bb1be7f8976104b9905eafa42d0e7.jpg

go-oop-inheritance-one-pet.jpeg

這則故事很簡單,但同時也暴露出一個問題,那就是在這場交易中,賣家實際上虧了,明明只是想買一個寵物,結果卻買了兩個!

當然,在上篇文中最後也給出瞭解決方案,那就是將貓和狗進行抽象封裝,共性的部分提取成寵物,個性的部分才是貓和狗.

如此一來,顧客買寵物時要麼買的是貓,要麼面對是狗,具體買的是什麼寵物是由顧客自己根據各自寵物的個性決定的,一定程度上解決了交易不公平的問題.

讓我們再簡單回憶一下繼承的實現過程,回憶的過程中不妨思考一下繼承有沒有沒能解決的問題?

  • 寵物預設自帶能文能武技能
type Pet struct {

}

func (p *Pet) Skill() {
    fmt.Println("能文能武的寵物")
}
  • 貓是寵物,還是能抓老鼠的寵物.
type Cat struct {
    p *Pet
}

func (c *Cat) Catch() {
    fmt.Println("老鼠天敵喵喵喵")
}
  • 狗是寵物,還是能認路導航的寵物.

type Dog struct {
    p *Pet
}

func (d *Dog) Navigate() {
    fmt.Println("自帶導航汪汪汪")
}

某一天,C要能文能武的寵物,最好還可以順便抓個老鼠,於是C選擇了喵喵喵!

func TestExtendInstance(t *testing.T) {
    p := new(Pet)
    c := new(Cat)
    c.p = p

    // 老鼠天敵喵喵喵
    c.Catch()
    // 能文能武的寵物
    c.p.Skill()
}

過了一陣子,C覺得貓除了抓老鼠別的什麼都不會,別人遛狗,我遛貓?

於是,想要一種能自帶導航功能的寵物,毫無疑問的是,選擇了狗.

func TestExtendInstance(t *testing.T) {
    p := new(Pet)
    d := new(Dog)
    d.p = p

    // 自帶導航汪汪汪
    d.Navigate()
    // 能文能武的寵物
    d.p.Skill()
}

上述示例,簡而言之就是通過組合的方式實現了物件導向中的繼承特性,解決了貓和狗除了是寵物還是自己的問題.

貓狗隨便是寵物就行

面對貓和狗兩種寵物,顧客犯了選擇困難症,於是第一次全盤照收買下了兩種寵物,吃了一次啞巴虧.

後來在市場監督的介入下,利用物件導向的繼承特性,用 Go 語言實現了貓和狗的個性化與寵物的共性化,從此像C一樣的顧客再也不會面臨選擇困難症,每一次都要根據獨特的需求,最終選擇某一種寵物,要麼是貓,要麼是狗.

不知過了多久,這種相安無事的場景最終被一群急性子的顧客所打破,這一天寵物市場一大早就來一大批人,一上來就吵吵嚷嚷說快給我們一批寵物,我們要作為抽獎活動的獎品,一定要快一點!

https://i.iter01.com/images/a6a5e9a3da3f24576447c8f917eea9710c1efa25b48355f3f9e848029df1af30.jpg

go-oop-interface-hurry.jpeg

誰知道銷售人員不緊不慢地說: "彆著急,我們這裡的寵物有很多種,有貓,有狗,有兔子,有金魚,有烏龜,有蝸牛..."

"別整那些虛頭巴腦的,我只要寵物,趕緊給我寵物就行,別盡扯沒用的",顧客吵吵說.

果然是一群急性子的顧客,還沒等銷售人員介紹完各個寵物的差異性亮點直接被打斷了.

寵物市場吵吵鬧鬧引來了市場監督人員的注意,顧客和商家均向官方訴苦,期望能給出一個解決辦法!

市場監督人員心想: 商家和顧客原本和諧相處的,今天怎麼會吵鬧起來?

仔細聽了事情來龍去脈,雙方都沒有過錯,看來還真的是市場趕不上實際需求的變化,真得儘快研究新的解決辦法才行啊!

https://i.iter01.com/images/bb7414c972779dfe1fcfbe92a8c61422a8983df7df0c7259269cc598fd6629f7.jpg

go-oop-interface-issue-new.jpg

"冷靜一下,你們的意見我們這邊已經知道了,這樣吧,給我們三天的時間,我們一定會想出一個萬全之策,到時候再公佈新的交易規則,現在我宣佈暫時關閉交易,省的再惹出不必要的爭端!"

原本吵吵嚷嚷的市場頓時冷卻了不少,畢竟誰也不敢違抗市場老大的命令,眾人只得悻悻而去,期待三天後的重新開市.

視角切換到市場監督大會上,主席首先開始發言:"各位,現在市場面臨的問題想必大家都有所耳聞吧,我們已經鄭重承諾,三天後必須給市場一個答覆,時間緊,任務重,大家要集思廣益,一起解決這個難題!"

https://i.iter01.com/images/e52952af40e52405210b33c256351dc95e3bc52f4796b6c8851bac3db1a18f8e.jpg

go-oop-interface-issue-meeting.jpg

"現在的顧客到底是怎麼了,連自己到底想要什麼都搞不清楚,還急衝衝地跑來買寵物,自己都不知道要買啥,鬼才知道呢!",資歷老練的繼承經理抱怨道.

"經理說得對,他們自己都不知道到底想要啥寵物,怎麼能埋怨商家太羅裡吧嗦呢?人家那麼賣力介紹寵物的特點,不也是幫助顧客更好的選擇嘛!",發言的是繼承經理的小弟.

"..."

"咳咳,我理解大家的心情,繼承專案組確實在解決寵物問題上立下了很大功勞,大家為他們抱不平也是情理之中的事情,過去的就讓他過去吧!當務之急,還是要解決現實問題!",主席首先安撫前幾位激動情緒,又挑出重點提醒在場的各位迴歸到主題的討論上,不要再揪住過去的功勞簿.

"我覺得,心急顧客的真正需求只是想要一種寵物,而不再關注寵物的種類,管他是貓是狗,只要是寵物就行.所以我們應該提供一種新的機制,對外宣傳時只說這是寵物,至於這種寵物到底是貓還是狗,都可以!"

"貓和狗明明已經是寵物了啊,難道不可以直接賣給顧客嗎?為啥還要提供新機制?"

"貓和狗雖然是寵物,但對於使用者來說,這種寵物有點浪費了,使用者實際使用到可能只是寵物的功能,並不會用到也不能用到具體寵物的功能,所以對使用者來說,這就是一種浪費."

"哦哦,明白了,這就像是顧客需要的寵物是能賣萌的,是要送給女朋友作為禮物的,並不關心這個寵物能不能抓老鼠.所以對於抓老鼠的技能就是沒用的,而買家卻要為抓老鼠的技能額外買單,這對於買家來說並不公平!"

經過一番激烈的討論,大家基本上達成一致,先前存在的繼承模型確實有些不足,不能適應快速變化的市場,過於強調差異性而非共性.

這樣就導致無法滿足急性子顧客批量購買的需求,所以需要提供類似於繼承那種抽象的概念來表達某種約定,只要滿足這種約定的動物就是寵,不管是貓還是狗,哪怕是玩具也行!

https://i.iter01.com/images/fe51fcc1ef777b440d772d0b98610b4b99bfc8d7658cf86c60ad7203262475c8.jpg

go-oop-interface-pet-toy.jpeg

讓繼承變得更加抽象

透過現象看本質,從紛繁冗雜的事務中抽象出精簡的模型是各個程式語言都必不可少的一個環節,Go 語言當然也不例外.

物件導向程式設計中的繼承概念表達是一種上下級的抽象關係,也就是說某一個封裝物件是從屬於特定上級的封裝物件,預設擁有該上級的行為方法,這裡的上級概念就是父類就是對所有子類共性的抽象實現.

當研究的問題就是具體的子類實現時,此時使用繼承的概念,語義上比較清晰,子類只需要關注自己的特性,共性部分由父類去完成,這種思路也是非常自然的,貓是貓的同時也是一種寵物.

https://i.iter01.com/images/4027f6492318aa7ce0cd081f8df5b56ebfcf6722ee4e68bc4543a394370e0697.jpg

go-oop-inheritance-one-cat.jpeg

但是當我們研究的問題不再關注具體的子類實現而是著眼於父類的共性時,此時如果再提供具體的子類實現當然也能用,但是殺雞焉用牛刀?

明明我僅僅需要一滴水,你卻給了我整個海洋!

https://i.iter01.com/images/4c8c1a6d4a7b63a0f00e8d6dec975023bdec521b32a0cc78724e80c8de10249d.jpg

go-oop-interface-water.jpeg

本來,真正需要的可能只是父類的某一個方法,你卻提供給我一個具體的子類實現,這個子類不但擁有目標方法還有很多的其他方法.

既然有這麼多的附加價值,你說浪費不浪費,銷售時可不得漲價嗎,這樣不相當於捆綁銷售了嘛!

所以,我們需要對繼承的概念進一步抽象,使這種抽象達到一種極致狀態以至於只存在非常少量的行為方法,凡是繼承自這種極致抽象的子類都是它的子民.

為了之後討論方便,業界將這種抽象到極致的繼承關係稱之為介面,雖然看似只是稱呼的改變,但實際上思維方式上已經發生了翻天覆地的變化.

繼承的概念是描述子類和父類的關係,子類繼承自父類,關注點在子類,共性部分完全由父類實現,子類自然擁有這些行為能力.

而介面的概念衍生於繼承,只不過是這種抽象程度已經達到了一種不能再抽象的地步,所有子類都要有一個最終的父類,這個父類擁有最公共性的行為方法,所以這種極致的抽象也就無法體現出子類的共性行為的具體表現.此時這種極致的抽象沒有太大的意義,是一種非常非常寬泛的概念,等於什麼都沒說,所以也適合絕大部分封裝物件.

所以,乾脆取消了極致抽象中對於行為共性的實現,轉而僅僅定義共性的行為,具體這種行為到底如何表現,完全由具體子類自行決定.

這樣做有兩個顯而易見的好處,一是解決了太寬泛概念等於沒說的尷尬,同時保留了對共性行為的描述.二是將控制權轉移到具體的子類實現,實現了體制內的個性化!

所以這種專業名詞的轉變背後是思維方式的轉變,而介面更是很好地描述了這種轉變的語義.

回憶一下生活總隨處可見的 USB 資料線,對於計算機來說,對外暴露的是 USB 插口,行為描述是隻要插入就能連線到電腦,能夠同電腦進行溝通交流,這種交流可能是傳遞資料,也可能是連線電源等等不同的行為表現.

https://i.iter01.com/images/697f84118f32618e83833ee4ad131e0784190777a74db2c2f2480cc1b7bc88f6.jpg

go-oop-interface-usb.jpg

基於介面設計,USB 資料線提供了訪問電腦的能力,一端連著電腦,另一端連著手機,雙方進行資料交換.
有線滑鼠的資料線也提供了訪問電腦的能力,實現滑鼠的左擊還是又擊都能反饋到電腦.

諸如此類的案例不勝列舉,生活中不缺少計算機哲學,缺少的只是我們的思考.

所以,如果讓我來給這種機制進行命名的話,我可能會將其稱呼為插口,意思是隻要能適配指定的插口,那麼就說滿足插口要求,對外暴露的抽象概念是插口,真正的實現可能是資料線或者工具等.

當然,這只是我的一廂情願,因為物件導向中這種機制叫做介面,滿足介面的規範叫做實現了介面.

介面這種概念顯得比較專業,提出這個概念的人估計也是厲害人物,基本上所有的面嚮物件語言中都採用了介面的概念,即使不是面嚮物件語言但支援物件導向程式設計風格的 Go 語言也採用了介面概念.

由此可見,介面的概念應該是通俗易懂,可移值性比較強的,獲得了相當高的認可度.

除了物件導向程式設計風格外,與介面相關的程式設計風格中還有一種叫做面向介面程式設計,這個會在以後的文章中繼續分享這封面的內容.

個人理解封裝和繼承的概念,講的就是物件導向程式設計,關注點在於具體的物件以及物件之間的層次關係.

而介面的出現則是另外一種維度的思考,當關注點不再是具體的子類而是抽象的父類,這種情況下則根據實際情況抽象出了介面的概念,由此看出,物件導向程式設計中高內聚部分說的是封裝和繼承,低耦合則是介面和多型.

所以面向介面程式設計在應用而生,由此可見,不同的應用場景關注點不同,物件導向和麵向介面也並不是互斥關係,是互補關係.

在未來的某種需求繼續發生改變時,可能還會產生新的概念,進而提出新的一套理論,到時候是面向需求程式設計還是面向思維程式設計亦或是面向搜尋程式設計,那就就不得而知了.

聰明的讀者,你們有什麼看法呢?

如何設計又怎麼實現

市場監督大會散會後,繼承小組接受了設計介面的任務挑戰.大會之所以推舉繼承小組領頭,是因為與會人員一致認為繼承小組在處理抽象概念上十分擅長,相信設計出介面這種機制也是可以的.

繼承小組深感此次任務責任重大,任重而道遠,一定要設計出介面概念才能不辜負參會人員的認可和領導的厚愛.

https://i.iter01.com/images/20e95adca7293e474dc1f77b182591203255cfaa67699fe5b117109f407192e2.jpg

go-oop-interface-dashing.jpg

於是,繼承小組內部在一起開了個會,會上大家暢所欲言談談自己的看法.

小王: "我覺得這種介面的概念是抽象的終極狀態,我們可能沒辦法一下子到達終點,但是按照現有的理論應該可以逐步逼近終點."
小李: "我也是有類似的感覺,抽象到什麼程度才是終點呢?拿什麼判定這個抽象程度呢?貓和狗到寵物的過程是一種抽象過程,我們先前也是基於此過程提出了繼承的概念,解決了重複定義的問題.現在應該沿著這種思路繼續抽象,直到小王說的那種介面概念."
小張: "從貓和狗抽象到寵物,是封裝物件的演進過程,顧客需要的不是具體的貓和狗,而是寵物.但是這個寵物直覺上感覺和原來繼承中實現的寵物還是有點不一樣啊?"
小王: "我也有同感,這次的寵物必須具備某種能力,只要是滿足這種能力的,管他是貓還是狗或者是別的什麼蜥蜴蟑螂的都是顧客眼中的寵物.所以這種寵物更加單一化,並不在乎有沒有其他能力."

...

大家你一言我一語的討論了好長時間,最終在專案經理的引導整理下有了有了初步的思路.

  • 介面是一種抽象,這種抽象可能並不關注父類本身的全部能力,只在於關注的能力.
  • 普通的抽象父類既有行為的約束還順便實現了該行為,但抽象到介面這種程度時是否實現並不在乎,但必須要有行為的約束.
  • 介面本身的語義是一種行為約束,滿足這種約束行為的具體物件可能會有很多,同時這些具體物件可能也滿足其他介面約束.
  • 介面約束變化時,滿足介面約束的具體子類到底要不要隨之變化?如果需要的話,有道理,如果不需要的話,也有道理.

"等一下,我有疑問?你怎麼一會說需要,一會又說不需要,這不自相矛盾了嗎?",大家幾乎不約而同舉手示意經理.似乎早就料到這幫小子搞不懂其中緣由,經理故弄玄虛地迴應說:"嗯嗯,我就知道你們會有疑惑,下面容我談一下我的看法,你們聽聽看.”

https://i.iter01.com/images/1d133c709853f5dc9737ed54f9e630f3a2f1a2faab587d0373e1f9a081b36fa5.jpg

go-oop-interface-expert.jpg

如果站在介面的定義者角度上看問題,一旦釋出了介面規範,子類肯定會屁顛屁顛滿足介面約束,於是對外暴露時都是介面那一套理論,忽略了自己的特色.

統一了介面規範這種情況對於介面設計者最為方便,所有的控制權全部掌握在自己手中,一道命令即可號令群雄,莫敢不從,如若不從,輕則千夫所指,重則驅逐出境!

對於介面設計者來說,這些實現了介面的物件並沒有什麼不同,地球離了誰照樣自轉,隨時隨地想換就換.

但是對於介面的實現類來說,只要一收到天子詔令,立馬無條件停下手上的活,熬夜加班也要滿足新的介面規範,敢怒不敢言,除非是不想混了,哪怕怠慢了一步也會引發巨大的動盪!

所以說介面更改時,具體的實現類必須要隨之改變以實現新的介面規範約束.

https://i.iter01.com/images/d52e0f7068cd81c723803cb2d59b2a630e5f1c9cdfafbbd8fe44eb692b74b43f.jpg

go-oop-interface-designer.jpeg

如果站在介面的使用者角度上看問題,是否實現介面應該是我的地盤我做主,是自主決定的事情,管你介面是否更改,老子愛實現就實現,不樂意實現就不實現!你奈我何?我的王國我當家,尊你敬你你才是國王,把我們惹惱了,所謂的聯合王國到時候只剩你這麼一個孤家寡人去吧!

所以說介面更改時,具體的實現類不需要隨之更改,想不想滿足新的介面規範完全在於自己,並不是強迫的,不必立即實現新的介面規範.

https://i.iter01.com/images/598b2947193f92db001d285efe1c00519e9a0ee739f014d60896ecdecce3ef89.png

go-oop-interface-impler.jpeg

真的是公說公有理婆說婆有理,既然如此,那麼問題來了,Go 語言選擇是哪一種?其他主流的程式語言又是選擇哪一種的呢?

先說其他主流的程式語言,這類程式語言大多是站在介面設計者角度出發,控制慾特別強,一言不合就報錯,介面更新了實現類必須同步更新,違令者殺無赦!

這樣有優點也有缺點,優點是皇帝一聲令下,天下臣民莫敢不從,屢教不敢者,千夫所指,王國崩潰也不是沒有可能!
正是這種優點,換另外一種角度看就是缺點了,俗話說天高皇帝遠,聖旨雖下但還沒傳達到邊境要塞,那邊監察御史就上奏你一本,說你怠政目無尊上,引發帝國動盪,罪大惡極,理應凌遲處死!

你說冤不冤,不管是朝令夕改還是煥然一新的改革,凡是曾經實現過介面的類都要實時更新,否則後果不堪設想.

真的是成也蕭何敗蕭何,控制慾太強有利有弊.

https://i.iter01.com/images/a5676c2b20d7b54a9ee2813149990abf089b398796fe028762348d8dbfbcae1f.jpg

go-oop-interface-xiaohe.jpg

所以,Go 與眾不同,選擇了另一種思路來解決問題,放棄中央集權轉向分封制,將權力下放給地方.

名義上還是由國王制定統一標準,由地方負責自主實施,具體如何實現標準完全是諸侯國自己的事情,萬一哪天國王需要使用統一標準時,實現了該標準的諸侯王國都可以無障礙使用.

即使以後介面規範有變,舊的介面不再適合新時代要求,國王只需要制定了一套新的標準,昭告天下後,當詔令傳到地方時,地方可以根據新的規範更新自己的實現類,萬一訊息閉塞或者不願意立即更新,也沒關係,王國不會崩潰,只不過需要使用新規範時,沒有實現介面的地方自然是不能使用的.

https://i.iter01.com/images/5e5939ba0f41b2b0c3d094c7e2c0ffeca6ecf0c2ed5285a9d8cf5788e9516f34.jpg

go-oop-interface-kingdom.jpg

因此,不論是集中制還是民主制,介面的規範都是自頂向下實施的,不同之處在於底下的人因各種原因沒有實現新的介面規範時,集中制會直接崩潰而民主制依舊正常執行,僅此而已.

下面就演示一下兩種思路的實現方式.

  • java 等傳統的面嚮物件語言

賣家首先定義到底什麼是寵物這種介面.

public interface Pet {
    void actingCute();
}

喵喵喵,人家能賣萌,就是寵物嘛,為啥還非得證明一下啊!

public static class Cat implements Pet {
    @Override
    public void actingCute() {
        System.out.println("喵星人喵喵喵來賣萌");
    }
}

這裡說的證明一下貓是寵物,指的是必須使用關鍵字 implements 宣告實現了寵物的介面,頒發了合格證才算是寵物,否則就不是.

汪星人說,這年頭自帶賣萌天賦的貓咪都要通過專業認證才算是寵物,我也乖乖去認證寵物吧!

public static class Dog implements Pet {
    @Override
    public void actingCute() {
        System.out.println("汪星人汪汪汪來賣萌");
    }
}

第二天,市場上又來了一群急性子的買家,一上來就要買寵物,管他是貓還是狗,並不在乎,只要是寵物就行.

public static void main(String[] args) {
    Pet p;
    
    p = new Cat();

    // 喵星人喵喵喵來賣萌
    p.actingCute();

    p = new Dog();

    // 汪星人汪汪汪來賣萌
    p.actingCute();
}

終於送走了這批顧客,賣家也舒了一口氣,默默唸叨著,市場監督那幫人真牛逼,竟然設計出介面的方案,只要是寵物,別管是貓還是狗,隨便給一個都行,給這幫人點個贊!

  • go 等非傳統非面嚮物件語言

首先定義介面規範,寵物一定要能賣萌,不然怎麼討得女神歡心?

type Pet interface {
    ActingCute()
}

喵喵喵說我會賣萌啊,那我就是寵物啦!

type Cat struct {

}

func (c *Cat) ActingCute() {
    fmt.Println("喵星人喵喵喵來賣萌")
}

汪汪汪說我也會賣萌,我也要給女神當寵物!

type Dog struct {

}

func (d *Dog) ActingCute() {
    fmt.Println("汪星人汪汪汪來賣萌")
}

既然你們都會賣萌,對於直男來說這就夠了,隨便拿一個就行了,快點準備送禮物啦!

func SendGift(p Pet) {
    p.ActingCute()
}

於是乎,既然買家並不在乎到底是貓還是狗,那就賣給他一個貓好了,於是小夥子打包了寵物準備送給女神.

func TestActingCute(t *testing.T) {
    var p Pet
    p = new(Cat)

    // 喵星人喵喵喵來賣萌
    SendGift(p)
}

第二天,女神打來電話說,你不知道對貓毛過敏的嗎,送的啥破禮物!哼!

可憐的小夥子跑去寵物店找賣家算賬,氣沖沖地質問賣家,賣家一臉毫不在意的樣子,笑嘻嘻的說,小夥子想不想將功補過啊,這一次保準你能獲得女神青睞.

只見,賣家這一次找來了一條寵物狗,打打包還放到原來的包裝盒遞給你小夥子.

func TestActingCute(t *testing.T) {
    var p Pet
    p = new(Dog)

    // 汪星人汪汪汪來賣萌
    SendGift(p)
}

我擦,還是原來的配方,有點擔心,一樣的包裝這一次真的能討得女神歡心,原諒自己嗎?

https://i.iter01.com/images/55bfc019cc5dbc618dc5352277da95c915a2764e4baaa3afdf1bd48b46937f41.jpg

go-oop-inheritance-one-dog.jpeg

親愛的讀者,你們說呢,同樣的配方不一樣的味道,女神會原諒自己嗎?

同一個問題思路不同

不論是站在設計者角度上解決抽象問題還是站在使用者角度思考,兩者的解決方案沒有高低優劣之分,選用好恰當的應用場景就是最好的解決方案.

只不過這種選擇往往不是開發者能左右的事情,因為這種底層的語言級別框架設計屬於締造者的工作,他們一旦覺得了一種模式,語言使用者很難改變,我們唯一能做的就是理解並使用罷了!

當站在介面設計者角度上時,介面的定義和具體實現類的關係就好比是集中制,皇帝一聲令下,不管身處何處,天下臣民皆惟命是從,如有懶政懈怠者,千夫所指,立馬崩潰.

當站在介面實現者角度上時,此時介面的設計者和具體實現者的關係是鬆耦合的,猶如分封制,國王一聲令下,諸侯國可以聽從差遣也可以抗旨不遵,對於整個王國而言並不會造成顛覆性混亂,諸侯國和國王更像是一種契約精神而不是隸屬服從關係.

Go 語言中的介面採用的就是後一種鬆耦合的關係,介面設計者和介面實現者是鬆耦合的,實現的關係也是隱式的,這也是另一種理論"鴨子模型"的體現.

https://i.iter01.com/images/d6900f0fa70c99c862cfe7ccb08214f9310a40325c68b39db238e2ec0e15fa2c.jpg

go-oop-interface-dock.jpg

好了,本文主要介紹了為什麼要有介面設計的需求以及介面設計是怎麼思考的,並簡單介紹了 Go 是如何實現這種模型的.

下一節我們將真正開始介紹 Go 語言關於介面的設計,順便講解物件導向最後一個知識點---多型.

如果本文對你理解物件導向有所幫助,歡迎你的的轉發分享,如果文章有描述不當之處,希望你能留言告訴我,謝謝你的閱讀.

https://i.iter01.com/images/63b68dce43b5be5999f209dbda5c51460af78c2cd2e805c120256e0b486686be.jpg

相關文章