1. 程式人生 > >Go語言中結構體的使用-第2部分OOP

Go語言中結構體的使用-第2部分OOP

1 概述

結構體的基本語法請參見:Go語言中結構體的使用-第1部分結構體
結構體除了是一個複合資料之外,還用來做面向物件程式設計。Go 語言使用結構體和結構體成員來描述真實世界的實體和實體對應的各種屬性。也就意味著結構體型別可以類比為其他語言中的“類class”, 而結構體資料可以類比為其他語言中的 “物件”。
本文就說說結構體中,面向物件的部分。

2 構造工廠函式

在面向物件程式設計中,例項化物件時往往需要完成很多業務邏輯,例如初始資料合理性,獲取需要的資源等。在經典的OOP程式中,都會提供構造方法,用於在例項化物件時完成特定功能。
Go語言中,沒有class,因此沒有典型意義的構造方法。但我們可以定義一個函式,用來例項化結構體物件,在函式內完成特定功能,實現建構函式的功能,這就是構造工廠函式。演示如下:

type Product struct {
    Name  string
    Price float64
}
func NewProduct(name string, price float64) *Product {
    // 此處完成初始化業務邏輯

    // 得到Product物件
    return &Product{
        Name: name,
        Price: price,
    }
}

// 需要 Product 物件時:
p := NewProduct("ThinkPad T480", 8008)

注意,在OOP程式設計中,通常認為物件是引用用傳遞,因此我們的建構函式返回的是 *Product

同時函式內使用 &Product ,這樣得到的物件為引用傳遞(Go語言對結構體型別自動解析引用)。

3 成員方法(接收器)

若要為成員增加方法,需要在函式上定義接收器,用來接收呼叫該方法的成員物件。接收器定義如下:

func (p *Product) Sale() {
  fmt.Println("Product: ", p.name, " is on Sale")
}

語法中,(p *Product) 就是接收器。通過定義可知,該接收器可以讓函式接受一個 *Product 型別的引數,也就是呼叫該函式的物件。呼叫方法為:

pro := &Product{
  name: "ThinkPad T480"
}
// 當作成員去呼叫
// 呼叫時,將呼叫函式的 pro,作為引數傳遞給函式 Run 的接收器 m。這樣就可以訪問 pro 物件了。
pro.Sale()

同樣,面向物件中物件通常為引用型別,因此接收器的定義也是 *Product 的引用型別。

4 繼承,內嵌結構體

Go語言中結構體物件間的繼承,通過內嵌結構體語法實現。演示:

type Product struct {
    Name  string
    Price float64
}
func (p *Product) Sale() {
  fmt.Println("Product: ", p.name, " is on Sale")
}
type Book struct {
  // 嵌入Product結構體
  Product
  Author string
  Publish string
}

定義 Book 時,內嵌了 Product 結構體。其中 Book 稱為子結構體(派生,擴充套件),Product成為父結構體(基礎)。例項化的 Book 結構體物件,可以直接訪問 Product 結構體中定義的成員包括屬性和方法。演示:

v := &Book{}
// 訪問內嵌結構體屬性
v.Name = "笑傲江湖"
v.Author = "金庸"
// 呼叫內嵌結構體方法
v.Sale()

內嵌還支援:
多繼承,可以同時內嵌多個結構體,稱之為多繼承。但要保證所繼承的結構體間沒有同名成員,否則出錯。

間接訪問,字結構體物件支援通過父結構體物件訪問繼承的成員,語法為 v.Product.Name,效果與 v.Name 一致。可以理解為是一種快捷語法。

直接初始化,可以直接為內嵌結構體提供初始化操作。演示為:

p := &Book{
  Product: &Product{
    Name: "天龍八部"
    Price: 42.8
  }
  Author: "金庸"
}

5 重寫,override

在內嵌繼承中,若子與父結構體存在同名成員,例項化的子結構體成員,訪問到的是字結構體定義的成員。這個現象稱之為重寫override。演示:

type Product struct {
    Name  string
    Price float64
}
func (p *Product) Sale() {
  fmt.Println("Product: ", p.name, " is on Sale")
}
type Book struct {
  // 嵌入Product結構體
  Product
  Author string
  Publish string
  Price float64
}
v := &Book{}
// 訪問內嵌結構體屬性
// 以下程式碼訪問的是 Book 中定義的 Price 屬性
v.Price = 42.8
// 測試:
fmt.Println(v.Product.Price) // 結果為 0

注意,繼承是一個查詢 過程。先在當前結構體物件中查詢,如果沒有向內嵌結構體中查詢,直到最內層內嵌結構體。重寫就是由於在當前結構體物件中查詢到了,就不需要再去嵌入結構體物件中查找了,不是一個成員替換過程。

結構體,例項化,繼承,重寫示意圖如下:
OOP

以上就是結構體提供的關於OOP中的語法。OOP程式設計還會涉及到介面,反射等技術。

結構體第二部分完!
原文出自:小韓說課
微信關注:小韓說課
小韓說課