搜尋
首頁後端開發GolangGolang 中的物件導向程式設計 (OOP) 簡介

當我們談論程式設計時,我們通常指的是編寫一堆修改某些資料並與某些資料互動的函數。物件導向程式設計(OOP)是一種程式設計模型,它專注於包含資料並附加一些相關功能的「物件」。物件導向程式設計有四大支柱:繼承、封裝、多態性與抽象。在本部落格中,我們將透過範例了解如何在 Golang 中實現它們中的每一個。推薦一些有關 OOP 的基本概念,但如果沒有,我將簡要介紹所有四個支柱的含義。

Introduction to Object Oriented Programming (OOP) in Golang

類別、物件和方法

物件導向程式設計的核心思想可以概括為以下幾點:

  • 您定義“類別”,它們是資料和可以呼叫該資料的函數的集合。
  • 這些特定的函數稱為該特定類別的「方法」。
  • 類別的實際實例稱為「物件」。

讓我們來看一些 Golang 中的程式碼來理解這三個概念:

package main

import "fmt"

type Batman struct {
    actor string
    year int
}

func (b Batman) SayImBatman() {
    fmt.Printf("I'm %s and I'm Batman from year %d\n", b.actor, b.year)
}

func main() {
    b1 := Batman{actor: "Michael Keaton", year: 1989}
    b2 := Batman{actor: "Christian Bale", year: 2005}

    b1.SayImBatman()
    b2.SayImBatman()
}

在Golang中,類別只不過是我們定義的型別。這些類型不一定必須是結構體,但通常都是結構體,因為在 OOP 中我們使用資料集合,這些資料可以是任何類型(字串、整數等)。

類別是物件的藍圖。每當實例化一個類別時,就會形成一個物件。在此範例中,b1 和 b2 是 Batman 類別的物件。

SayImBatman 函數可以在該類別的任何物件上呼叫。由於它與 Batman 類別相關,因此不稱之為常規函數,而是稱為類別的方法

我認為這應該足以讓您清楚 OOP 的基礎知識,以便您繼續進行下一部分,我們將在其中介紹 OOP 的四大支柱。

遺產

繼承引入了 OOP 中 parentchild 類別的概念。子類別是從父類別派生的類,並繼承其所有方法和屬性(資料)。讓我們來看看一些程式碼來幫助我們理解這一點:

package main

import "fmt"

type Hero struct {
    team string
}

type Batman struct {
    Hero
    name string
}

type Ironman struct {
    Hero
    power int
}

func (h Hero) SayTeam() {
    fmt.Println("My Team is", h.team)
}

func (b Batman) SayImBatman() {
    fmt.Printf("I'm %s and I'm Batman\n", b.name)
}

func (i Ironman) SayPowerLevel() {
    fmt.Printf("I'm Ironman and my powerlevel is %d\n", i.power)
}

func main() {
    b1 := Batman{Hero{team: "Justice League"}, "Christian Bale"}
    i1 := Ironman{Hero{team: "Avengers"}, 23}

    b1.SayImBatman()
    b1.SayTeam()

    i1.SayPowerLevel()
    i1.SayTeam()
}

在此範例中,蝙蝠俠和鋼鐵人是 Hero 父類的子類別。他們可以存取其父類別的屬性(即 team)及其方法(即 SayTeam)。正如您在聲明 b1 和 i1 實例時所看到的那樣,我們指定了父類別屬性以及它們各自類別的特定屬性。它們都能夠呼叫父類別中定義的 SayTeam 方法。但它們也有各自獨特的屬性和方法。

Golang 使用組合(在結構體中使用結構體)來實現繼承。它不像其他 OOP 語言(例如 C 或 Java)那樣具有內建的基於類別的繼承。

封裝

封裝是隱藏物件內部屬性且不允許直接修改它們的原理。相反,它依賴於提供獲取和更新這些屬性的方法。讓我們看一個例子來更好地理解這一點:

package main

import "fmt"

type Batman struct {
    actor string
    year int
}

func (b Batman) SayImBatman() {
    fmt.Printf("I'm %s and I'm Batman from year %d\n", b.actor, b.year)
}

func main() {
    b1 := Batman{actor: "Michael Keaton", year: 1989}
    b2 := Batman{actor: "Christian Bale", year: 2005}

    b1.SayImBatman()
    b2.SayImBatman()
}

package main

import "fmt"

type Hero struct {
    team string
}

type Batman struct {
    Hero
    name string
}

type Ironman struct {
    Hero
    power int
}

func (h Hero) SayTeam() {
    fmt.Println("My Team is", h.team)
}

func (b Batman) SayImBatman() {
    fmt.Printf("I'm %s and I'm Batman\n", b.name)
}

func (i Ironman) SayPowerLevel() {
    fmt.Printf("I'm Ironman and my powerlevel is %d\n", i.power)
}

func main() {
    b1 := Batman{Hero{team: "Justice League"}, "Christian Bale"}
    i1 := Ironman{Hero{team: "Avengers"}, 23}

    b1.SayImBatman()
    b1.SayTeam()

    i1.SayPowerLevel()
    i1.SayTeam()
}

在Golang中,從套件中導出的屬性和方法以大寫字母開頭。當我們在utils包中定義小寫的actor和year時,我們確保它們不能被直接修改。相反,就像您在 main.go 檔案中看到的那樣,您需要使用匯出的方法(以大寫字母開頭) - GetActor、SetActor 等來獲取和修改它們。

這就是封裝的全部內容 - 確保防止資料意外更改,並提供與資料安全互動的方法。

您會注意到不同的一件事是,在 Batman 類別的所有方法中,我們使用指標接收器 *Batman 而不是像前面範例中那樣使用值接收器 Batman。這是因為我們希望能夠在 Set 方法中修改原始結構。在 Golang 中,最佳實踐是,如果某些方法需要指標接收器,則讓所有方法都使用指標接收器以保持一致性。這就是為什麼 Get 方法也使用指標接收器,即使它們沒有修改原始結構。

此外,還要注意的一件事是,僅僅因為我們使用的是指標接收器,我們就不必這樣做:(&b1).GetActor。在 Golang 中,帶有指針參數的函數必須採用指針,但帶有指針接收器的方法可以採用值或指針作為接收器。

TL;DR:Golang 自動將b1.GetActor 轉換為(&b1).GetActor,因為GetActor 方法有一個指標接收器,但如果GetActor 是一個普通函數,它不會將GetActor(b1) 轉換為GetActor( &b1)一個指標參數。

多態性與抽象

OOP 的接下來兩個支柱可以合併在一起,因為它們的程式碼範例看起來非常相似。多態性是指兩個不同類別的兩個不同物件可以被視為同一公共超類別的物件的程式設計實踐。這意味著您可以在兩個不同的物件上呼叫相同的函數,就好像它們是同一類別的物件一樣。這應該開始讓您感受到所涉及的介面的味道:)

讓我們看一些程式碼來更好地理解這一點:

package main

import "fmt"

type Batman struct {
    actor string
    year int
}

func (b Batman) SayImBatman() {
    fmt.Printf("I'm %s and I'm Batman from year %d\n", b.actor, b.year)
}

func main() {
    b1 := Batman{actor: "Michael Keaton", year: 1989}
    b2 := Batman{actor: "Christian Bale", year: 2005}

    b1.SayImBatman()
    b2.SayImBatman()
}

在此範例中,StartFight 函數可以傳遞 b1 和 i1 對象,即使它們彼此沒有任何關係。試著理解這與繼承有何不同,在繼承中,子類別可以存取父類別的方法。在此範例中,沒有子類別和父類別(也沒有共用方法)。相反,兩個不同的物件被函數視為相同:這稱為多態性。

現在,這也可以被視為抽象的例子。顧名思義,抽像是一種隱藏實作細節,而只是提供為您處理事務的函數的程式設計實踐。在這個例子中,你不需要關心單一英雄的方法是如何被配置的。當您想使用任何英雄的戰鬥功能時,您可以隨時繼續使用開始戰鬥功能。這樣,實作細節對使用者來說是隱藏的,只暴露基本的細節。

現在回到多態,有兩個更常見的例子,那就是方法重寫和重載。

方法重寫

方法重寫是指子類別定義自己的父類別中定義的方法的實作。現在使用此實作來代替原始父類別的實作。讓我們看看之前用於繼承的程式碼,看看它在方法重寫後的樣子:

package main

import "fmt"

type Hero struct {
    team string
}

type Batman struct {
    Hero
    name string
}

type Ironman struct {
    Hero
    power int
}

func (h Hero) SayTeam() {
    fmt.Println("My Team is", h.team)
}

func (b Batman) SayImBatman() {
    fmt.Printf("I'm %s and I'm Batman\n", b.name)
}

func (i Ironman) SayPowerLevel() {
    fmt.Printf("I'm Ironman and my powerlevel is %d\n", i.power)
}

func main() {
    b1 := Batman{Hero{team: "Justice League"}, "Christian Bale"}
    i1 := Ironman{Hero{team: "Avengers"}, 23}

    b1.SayImBatman()
    b1.SayTeam()

    i1.SayPowerLevel()
    i1.SayTeam()
}

程式的輸出是:

//oops-in-go/utils/utils.go

package utils

type Batman struct {
    actor string
    year int
}

func (b *Batman) GetActor() string {
    return b.actor
}

func (b *Batman) GetYear() int {
    return b.year
}

func (b *Batman) SetActor(actor string) {
    b.actor = actor
}

func (b *Batman) SetYear(year int) {
    b.year = year
}

Batman 類別的物件現在使用自己的 SayTeam 方法,而不是父 Hero 類別的方法。由於 Ironman 類別沒有自己的 SayTeam 方法,因此它的物件仍然使用其父類別的方法。這就是方法重寫的意思,子類別「重寫」父類別中定義的方法。

方法重載

這是指同一個函數能夠接受多個不同的參數。這些參數的數量或類型可能不同。 Golang 提供了兩種方法來實現這一點:透過可變參數函數,另一種透過介面。

讓我們來看看兩者的程式碼,這將幫助您更好地理解:

使用可變參數函數

// oops-in-go/main.go

package main

import (
    "fmt"
    "oops-in-go/utils"
)

func main() {
    b1 := utils.Batman{}
    b1.SetActor("Michael Keaton")
    b1.SetYear(1989)
    fmt.Printf("I'm %s and I'm Batman from year %d\n", b1.GetActor(), b1.GetYear())

    b1.SetActor("Christian Bale")
    b1.SetYear(2005)
    fmt.Printf("I'm %s and I'm Batman from year %d\n", b1.GetActor(), b1.GetYear())
}

在這裡,您可以使用任意數量個參數「重載」listMembers函數。

使用介面

package main

import "fmt"

type Hero interface {
    Fight()
}

type Batman struct {
    weapon string
}

type Ironman struct {
    weapon string
}

func (b Batman) Fight() {
    fmt.Printf("Batman hits with a %s\n", b.weapon)
}

func (i Ironman) Fight() {
    fmt.Printf("Ironman hits with a %s\n", i.weapon)
}

func StartFight(h Hero) {
    fmt.Println("Fight has started.")
    h.Fight()
}

func main() {
    b1 := Batman{"Batarang"}
    i1 := Ironman{"Repulsor rays"}

    StartFight(b1)
    StartFight(i1)
}

程式的輸出是:

package main

import "fmt"

type Hero struct {
    team string
}

type Batman struct {
    Hero
    name string
}

type Ironman struct {
    Hero
    power int
}

func (h Hero) SayTeam() {
    fmt.Println("My Team is", h.team)
}

func (b Batman) SayImBatman() {
    fmt.Printf("I'm %s and I'm Batman\n", b.name)
}

func (i Ironman) SayPowerLevel() {
    fmt.Printf("I'm Ironman and my powerlevel is %d\n", i.power)
}

func (b Batman) SayTeam() {
    fmt.Printf("I'm Batman and my team is %s\n", b.team)
}

func main() {
    b1 := Batman{Hero{team: "Justice League"}, "Christian Bale"}
    i1 := Ironman{Hero{team: "Avengers"}, 23}

    b1.SayImBatman()
    b1.SayTeam()

    i1.SayPowerLevel()
    i1.SayTeam()
}

這裡我們「重載」了 saySomething 方法來接受不同類型的參數。我們採用一個空介面作為參數,它可以是任何類型,然後使用 switch case 檢查其類型並相應地列印輸出。

結論

我很清楚這是一篇很長的文章,如果您堅持讀到最後,我想讓您知道我真的很高興:) 我真誠地希望您學到很多有關面向對象編程的新知識以及如何在Golang 中實現它。我在我的網站上撰寫有關不同技術概念的博客,如果您有興趣學習新事物,我建議您訂閱我的時事通訊。

以上是Golang 中的物件導向程式設計 (OOP) 簡介的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
掌握GO弦:深入研究'字符串”包裝掌握GO弦:深入研究'字符串”包裝May 12, 2025 am 12:05 AM

你應該關心Go語言中的"strings"包,因為它提供了處理文本數據的工具,從基本的字符串拼接到高級的正則表達式匹配。 1)"strings"包提供了高效的字符串操作,如Join函數用於拼接字符串,避免性能問題。 2)它包含高級功能,如ContainsAny函數,用於檢查字符串是否包含特定字符集。 3)Replace函數用於替換字符串中的子串,需注意替換順序和大小寫敏感性。 4)Split函數可以根據分隔符拆分字符串,常用於正則表達式處理。 5)使用時需考慮性能,如

GO中的'編碼/二進制”軟件包:您的二進制操作首選GO中的'編碼/二進制”軟件包:您的二進制操作首選May 12, 2025 am 12:03 AM

“編碼/二進制”軟件包interingoisentialForHandlingBinaryData,oferingToolSforreDingingAndWritingBinaryDataEfficely.1)Itsupportsbothlittle-endianandBig-endianBig-endianbyteorders,CompialforOss-System-System-System-compatibility.2)

Go Byte Slice操縱教程:掌握'字節”軟件包Go Byte Slice操縱教程:掌握'字節”軟件包May 12, 2025 am 12:02 AM

掌握Go語言中的bytes包有助於提高代碼的效率和優雅性。 1)bytes包對於解析二進制數據、處理網絡協議和內存管理至關重要。 2)使用bytes.Buffer可以逐步構建字節切片。 3)bytes包提供了搜索、替換和分割字節切片的功能。 4)bytes.Reader類型適用於從字節切片讀取數據,特別是在I/O操作中。 5)bytes包與Go的垃圾回收器協同工作,提高了大數據處理的效率。

您如何使用'字符串”軟件包在GO中操縱字符串?您如何使用'字符串”軟件包在GO中操縱字符串?May 12, 2025 am 12:01 AM

你可以使用Go語言中的"strings"包來操縱字符串。 1)使用strings.TrimSpace去除字符串兩端的空白字符。 2)用strings.Split將字符串按指定分隔符拆分成切片。 3)通過strings.Join將字符串切片合併成一個字符串。 4)用strings.Contains檢查字符串是否包含特定子串。 5)利用strings.ReplaceAll進行全局替換。注意使用時要考慮性能和潛在的陷阱。

如何使用'字節”軟件包在GO中操縱字節切片(逐步)如何使用'字節”軟件包在GO中操縱字節切片(逐步)May 12, 2025 am 12:01 AM

ThebytespackageinGoishighlyeffectiveforbyteslicemanipulation,offeringfunctionsforsearching,splitting,joining,andbuffering.1)Usebytes.Containstosearchforbytesequences.2)bytes.Splithelpsbreakdownbyteslicesusingdelimiters.3)bytes.Joinreconstructsbytesli

Go Bytes軟件包:有什麼選擇?Go Bytes軟件包:有什麼選擇?May 11, 2025 am 12:11 AM

thealternativestogo'sbytespackageincageincludethestringspackage,bufiopackage和customstructs.1)thestringspackagecanbeusedforbytemanipulationforbytemanipulationbybyconvertingbytestostostostostostrings.2))

操縱字節切片在GO:'字節”軟件包的功能操縱字節切片在GO:'字節”軟件包的功能May 11, 2025 am 12:09 AM

“字節”包裝封裝forefforeflyManipulatingByteslices,CocialforbinaryData,網絡交易和andfilei/o.itoffersfunctionslikeIndexForsearching,BufferForhandLinglaRgedLargedLargedAtaTasets,ReaderForsimulatingStreamReadReadImreAmreadReamReadinging,以及Joineffiter和Joineffiter和Joineffore

Go Strings套餐:弦樂操縱的綜合指南Go Strings套餐:弦樂操縱的綜合指南May 11, 2025 am 12:08 AM

go'sstringspackageIscialforficientficientsTringManipulation,uperingToolSlikestrings.split(),strings.join(),strings.replaceall(),andStrings.contains.contains.contains.contains.contains.contains.split.split(split()strings.split()dividesStringoSubSubStrings; 2)strings.joins.joins.joinsillise.joinsinelline joinsiline joinsinelline; 3);

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器