go 學習筆記之是否支持以及如何實現繼承

熟悉面向對象的小夥伴們可能會知道封裝,繼承和多態是最主要的特性,爲何前輩們會如此看重這三種特性,真的那麼重要嗎?編程

go-oop-inheritance-concept.jpeg

什麼是封裝

什麼是封裝,封裝有什麼好處以及怎麼實現封裝?數據結構

相信大多數小夥伴們都有本身的理解,簡而言之,言而簡之,封裝是屏蔽內部實現細節,僅僅對外暴露出有價值接口.編程語言

go-oop-inheritance-computer.jpeg

正如平時工做中使用的電腦同樣,咱們並不關心電腦的內部組成,只要會開機關機等基本操做就能正常使用電腦,即使壞了的話,也是送去專業維修店進行修理,做爲使用者來講,咱們從始至終並不關心電腦的工做原理以及它如何工做,惟一在意的就是怎麼可以上網.oop

go-oop-inheritance-computer-online.jpeg

之因此咱們能如何方便地使用電腦進行網上衝浪,徹底得益於電腦設計者對普通用戶屏蔽了無關細節,只暴露有價值的操做方法,這種實現方式就是封裝.學習

回到編程語言上,Go 語言做爲一種通用的編程語言,和其餘主流的編程語言同樣支持封裝,Go 語言關於封裝的實現主要包括兩部分:spa

  • 數據結構的封裝
  • 行爲方法的控制

其中數據結構的封裝主要是使用結構體關鍵字 struct 實現,而行爲方法的控制是用首字母大小寫區分是否對外可見.設計

關於 Go 如何實現封裝的細節,能夠參考前一篇文章: go 學習筆記之詳細說一說封裝是怎麼回事

繼承是怎麼回事

說完封裝,接着說一下繼承是怎麼回事?3d

繼承正是在封裝的基礎上逐步發展產生的概念,咱們知道封裝是對某一類行爲事物模型的抽象,而這種抽象偏偏是由人定義實現的,因人而異也就致使了封裝並無統一的標準答案.code

go-oop-inheritance-diff-anyone.jpeg

因而乎就可能存在着這麼一種狀況,對於生活中常見的貓和狗,兩我的分別有兩種封裝方式:對象

A: 貓是一種寵物,淘氣可愛會賣萌,看家本領抓老鼠,偶爾還會喵喵喵.

go-oop-inheritance-one-cat.jpeg

B: 狗是一種寵物,忠實聽話能看家,嗅覺靈敏會破案,一言不合汪汪汪.

go-oop-inheritance-one-dog.jpeg

C: 我想要買一個寵物,文能賣萌,武可退敵,明個一早給我送來吧!

go-oop-inheritance-one-pet.jpeg

因爲客戶C並無特別說明要的是貓仍是狗,A覺得是貓,由於貓安靜的時候很萌很可愛,生氣的時候用小爪爪撓你!
B覺得是狗,汪星人的名氣可不是自吹自擂,真的要惹怒了它,咬住不放能生生撕下一塊肉,你說這種武力值強不強大?

因而次日,客戶C懵逼了,怎麼一會兒送來了貓狗兩個寵物啊,但是又不能食言,由於A和B說的都有道理啊!

go-oop-inheritance-no-word.jpeg

等 A和 B走了後,C望着送來的貓和狗,不由陷入了深思:我只是想要一個寵物而已,非要給我貓和狗兩個選擇,我有選擇困難症啊!

go-oop-inheritance-hard-choose.jpeg

說完這個故事,剛開始會以爲有些滑稽,C只要隨便選擇一種寵物不就行了嗎,幹嗎非要全盤接收弄得本身不開心呢?

不知道正在看的讀者有沒有選擇困難症的經歷,面對多種選擇,一時不知道到底選擇哪個,最終結果可能有三種狀況:全盤確定,全盤否認和部分確定.

上述故事中,C選擇的是全盤確定,A和B送來的貓和狗都是寵物,沒理由拒絕任何一個,因而C選擇全盤確定,固然至於之後是否後悔只有 C本身內心清楚.

前車可鑑能夠爲師矣,若是下次咱們也遇到這種狀況應該如何選擇呢?

相信聰明的你心中已經有了本身的答案,大聲的說出來吧!我就要喵喵喵!

go-oop-inheritance-one-cat.jpeg

上述案例就比如同事間一塊兒去吃飯,點餐時問你點些什麼?你說隨便!

本來是好意,覺得能本身這麼說能方便其餘人,其實這種看似不挑剔的作法,對他人來講可能也是最難辦的事情.

由於隨便的範圍太寬泛了,什麼均可以也就意味着很大可能上並不會令你滿意,你在方便別人的同時,他人也在想法設法取悅於你,不知道你的喜愛,內心就犯嘀咕了,這個他喜不喜歡吃呢?

因此,請不要再說隨便,勇敢亮出你的觀點態度,哪怕不被承認知足.

故事中 A以爲貓是寵物,B以爲狗是寵物,於是當客戶真的要寵物時,A和 B都把各自的寵物送上去了,所以問題出如今寵物的定義上,到底什麼算是寵物?

其實C心中已經有了寵物的定義,那就是"文能賣萌,武可退敵",而貓和狗剛好都具有這種特性,所以對外宣傳時就不要再說這種默認的屬性,應該亮出本身的特點!

A: 貓會抓老鼠
B: 狗能認清路

C: 我要一種寵物,出現意外時能幫助到個人話,那就再好不過了!

若是一開始他們就這樣說的話,C真正須要的寵物究竟是貓仍是狗就一目瞭然了,也不會陷入選擇困難症了!

如何實現繼承

回到封裝的話題上來,轉換成編程語言就是A把貓封裝成寵物了,B把狗封裝成寵物了,而 C須要寵物時,貓和狗都是寵物,最終結果要麼是程序依舊正常運行,要麼是程序意外掛掉了,由於極可能某一種寵物可能並不符合特定需求.

這種重複定義問題歸咎於封裝的標準不一樣,貓和狗二者的封裝過程是獨立進行的,並無在一塊兒商量着看看能不能繼續抽象出通用模型,混亂的封裝致使了貓是寵物,狗也是寵物.

這種多種相關概念的封裝很容易出現此類問題,因此適當進行統一分析繼續抽象出更高層次的封裝概念尤其重要,基於此,原來的封裝就能從這種通用概念中解放出來,僅僅保留本身的特點就好,大大簡化了模型的語義.

普通封裝的概念和更高層次的抽象封裝概念的關係就是面向對象中的繼承,即貓繼承於寵物,表示貓不但擁有寵物的特色還有貓本身的亮點.

對於狗也是同樣,狗是寵物,狗也是狗本身自己,體現了本身的特色.

Go 語言和其餘主流的面嚮對象語言有所不一樣,Go 並不支持繼承特性,於是也沒有單繼承,多繼承,重寫方法等複雜概念.

Go 是如何描述這種普通封裝和抽象封裝之間的關係呢?

確定不是把貓定義成寵物,狗也定義成寵物那種方式!

Go 實現繼承的語義不是經過 extends 關鍵字而是經過結構體組合的方式,請看相關代碼.

  • 寵物就應該能文能武,這裏不關心結構體的字段,於是並無定義相關字段.
type Pet struct {
}

func (p *Pet) Skill() {
    fmt.Println("能文能武的寵物")
}
  • 貓是可以抓老鼠的寵物,Go 採用組合的方式表達繼承的語義.
type Cat struct {
    p *Pet
}

func (c *Cat) Catch() {
    fmt.Println("老鼠天敵喵喵喵")
}
  • 狗是自帶導航功能的寵物,看我導盲犬的超能力!
type Dog struct {
    p *Pet
}

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

接下來,C開始檢驗貓和狗做爲寵物是否具有能文能武的基本要求,與此同時有沒有自身的特點?

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

    d := new(Dog)
    d.p = p

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

    fmt.Println()

    c := new(Cat)
    c.p = p

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

上述結果證實,Go 語言雖然不支持 extends 關鍵字表達的繼承特性,可是採用組合的方式也是能夠實現繼承語義的,畢竟,黑貓仍是白貓,抓住老鼠的纔是好貓!

面向對象的封裝和繼承暫時告一段落,下一篇文章中將開始講解接口,以及面向對象中最後的一個概念: 多態!

感謝你的閱讀,若是本文對你有所幫助,還望你能留言告訴我,也歡迎分享轉發喲!

雪之夢技術驛站.png

相關文章
相關標籤/搜索