16. 理解 Go 語言面向對象編程:接口與多態

Hi,你們好,我是明哥。git

在本身學習 Golang 的這段時間裏,我寫了詳細的學習筆記放在個人我的微信公衆號 《Go編程時光》,對於 Go 語言,我也算是個初學者,所以寫的東西應該會比較適合剛接觸的同窗,若是你也是剛學習 Go 語言,不防關注一下,一塊兒學習,一塊兒成長。github

個人在線博客: http://golang.iswbm.com
個人 Github:github.com/iswbm/GolangCodingTime

0. 接口是什麼?

這一段摘自 Go語言中文網

在面向對象的領域裏,接口通常這樣定義:接口定義一個對象的行爲。接口只指定了對象應該作什麼,至於如何實現這個行爲(即實現細節),則由對象自己去肯定。golang

在 Go 語言中,接口就是方法簽名(Method Signature)的集合。當一個類型定義了接口中的全部方法,咱們稱它實現了該接口。這與面向對象編程(OOP)的說法很相似。接口指定了一個類型應該具備的方法,並由該類型決定如何實現這些方法編程

1. 如何定義接口

使用 type 關鍵字來定義接口。數組

以下代碼,定義了一個電話接口,接口要求必須實現 call 方法。微信

type Phone interface {
   call()
}

2. 如何實現接口

若是有一個類型/結構體,實現了一個接口要求的全部方法,這裏 Phone 接口只有 call方法,因此只要實現了 call 方法,咱們就能夠稱它實現了 Phone 接口。函數

意思是若是有一臺機器,能夠給別人打電話,那麼咱們就能夠把它叫作電話。學習

這個接口的實現是隱式的,不像 JAVA 中要用 implements 顯示說明。spa

繼續上面電話的例子,咱們先定義一個 Nokia 的結構體,而它實現了 call 的方法,因此它也是一臺電話。3d

type Nokia struct {
    name string
}

// 接收者爲 Nokia
func (phone Nokia) call() {
    fmt.Println("我是 Nokia,是一臺電話")
}

3. 接口實現多態

鴨子類型(Duck typing)的定義是,只要你長得像鴨子,叫起來也像鴨子,那我認爲你就是一隻鴨子。

舉個通俗的例子

什麼樣子的人能夠稱作老師呢?

不一樣的人標準不一,有的人認爲必須有必定的學歷,有的人認爲必需要有老師資格證。

而我認爲只要能育人,能給傳授給其餘人知識的,均可以稱之爲老師。

而無論你教的什麼學科?是體育競技,仍是教人烹飪。

也無論你怎麼教?是在教室裏手執教教鞭、拿着粉筆,仍是追求真實,直接實戰演練。

統統無論。

這就一個接口(老師)下,在不一樣對象(人)上的不一樣表現。這就是多態。

在 Go 語言中,是經過接口來實現的多態。

這裏以商品接口來寫一段代碼演示一下。

先定義一個商品(Good)的接口,意思是一個類型或者結構體,只要實現了settleAccount()orderInfo() 兩個方法,那這個類型/結構體就是一個商品。

type Good interface {
    settleAccount() int
    orderInfo() string
}

而後咱們定義兩個結構體,分別是手機和贈品。

type Phone struct {
    name string
    quantity int
    price int
}

type FreeGift struct {
    name string
    quantity int
    price int
}

而後分別爲他們實現 Good 接口的兩個方法

// Phone
func (phone Phone) settleAccount() int {
    return phone.quantity * phone.price
}
func (phone Phone) orderInfo() string{
    return "您要購買" + strconv.Itoa(phone.quantity)+ "個" + 
        phone.name + "計:" + strconv.Itoa(phone.settleAccount()) + "元"
}

// FreeGift
func (gift FreeGift) settleAccount() int {
    return 0
}
func (gift FreeGift) orderInfo() string{
    return "您要購買" + strconv.Itoa(gift.quantity)+ "個" + 
        gift.name + "計:" + strconv.Itoa(gift.settleAccount()) + "元"
}

實現了 Good 接口要求的兩個方法後,手機和贈品在Go語言看來就都是商品(Good)類型了。

這裏候,我挑選了兩件商品(實例化),分別是手機和耳機(贈品,不要錢)

iPhone := Phone{
    name:     "iPhone",
    quantity: 1,
    price:    8000,
}
earphones := FreeGift{
    name:     "耳機",
    quantity: 1,
    price:    200,
}

而後建立一個購物車(也就是類型爲 Good的切片),來存放這些商品。

goods := []Good{iPhone, earphones}

最後,定義一個方法來計算購物車裏的訂單金額

func calculateAllPrice(goods []Good) int {
    var allPrice int
    for _,good := range goods{
        fmt.Println(good.orderInfo())
        allPrice += good.settleAccount()
    }
    return allPrice
}

完整代碼,我貼在下面,供你參考。

package main

import (
    "fmt"
    "strconv"
)

// 定義一個接口
type Good interface {
    settleAccount() int
    orderInfo() string
}

type Phone struct {
    name string
    quantity int
    price int
}

func (phone Phone) settleAccount() int {
    return phone.quantity * phone.price
}
func (phone Phone) orderInfo() string{
    return "您要購買" + strconv.Itoa(phone.quantity)+ "個" + 
        phone.name + "計:" + strconv.Itoa(phone.settleAccount()) + "元"
}

type FreeGift struct {
    name string
    quantity int
    price int
}

func (gift FreeGift) settleAccount() int {
    return 0
}
func (gift FreeGift) orderInfo() string{
    return "您要購買" + strconv.Itoa(gift.quantity)+ "個" + 
        gift.name + "計:" + strconv.Itoa(gift.settleAccount()) + "元"
}

func calculateAllPrice(goods []Good) int {
    var allPrice int
    for _,good := range goods{
        fmt.Println(good.orderInfo())
        allPrice += good.settleAccount()
    }
    return allPrice
}
func main()  {
    iPhone := Phone{
        name:     "iPhone",
        quantity: 1,
        price:    8000,
    }
    earphones := FreeGift{
        name:     "耳機",
        quantity: 1,
        price:    200,
    }

    goods := []Good{iPhone, earphones}
    allPrice := calculateAllPrice(goods)
    fmt.Printf("該訂單總共須要支付 %d 元", allPrice)
}

運行後,輸出以下

您要購買1個iPhone計:8000元
您要購買1個耳機計:0元
該訂單總共須要支付 8000 元

系列導讀

01. 開發環境的搭建(Goland & VS Code)

02. 學習五種變量建立的方法

03. 詳解數據類型:整形與浮點型

04. 詳解數據類型:byte、rune與string

05. 詳解數據類型:數組與切片

06. 詳解數據類型:字典與布爾類型

07. 詳解數據類型:指針

08. 面向對象編程:結構體與繼承

09. 一篇文章理解 Go 裏的函數

10. Go語言流程控制:if-else 條件語句

11. Go語言流程控制:switch-case 選擇語句

12. Go語言流程控制:for 循環語句

13. Go語言流程控制:goto 無條件跳轉

14. Go語言流程控制:defer 延遲調用

15. 面向對象編程:接口與多態

16. 關鍵字:make 和 new 的區別?

17. 一篇文章理解 Go 裏的語句塊與做用域

18. 學習 Go 協程:goroutine

19. 學習 Go 協程:詳解信道/通道

20. 幾個信道死鎖經典錯誤案例詳解

21. 學習 Go 協程:WaitGroup

22. 學習 Go 協程:互斥鎖和讀寫鎖

23. Go 裏的異常處理:panic 和 recover

24. 超詳細解讀 Go Modules 前世此生及入門使用

25. Go 語言中關於包導入必學的 8 個知識點

26. 如何開源本身寫的模塊給別人用?

27. 說說 Go 語言中的類型斷言?

28. 這五點帶你理解Go語言的select用法


相關文章
相關標籤/搜索