ホームページ バックエンド開発 Golang Golang のオブジェクト指向プログラミング (OOP) の概要

Golang のオブジェクト指向プログラミング (OOP) の概要

Dec 23, 2024 pm 12:43 PM

プログラミングについて話すとき、私たちは通常、データを変更したり操作したりする一連の関数を書くことを意味します。オブジェクト指向プログラミング (OOP) は、データを含み、関連する機能がいくつか関連付けられている「オブジェクト」に焦点を当てたプログラミング モデルです。オブジェクト指向プログラミングには、継承、カプセル化、ポリモーフィズム、抽象化という 4 つの柱があります。このブログでは、Golang でそれぞれを実装する方法を例を挙げて見ていきます。 OOP に関するいくつかの基本的な考え方をお勧めしますが、そうでない場合は、4 つの柱すべてが何を意味するのかについて簡単に説明します。

Introduction to Object Oriented Programming (OOP) in Golang

クラス、オブジェクト、メソッド

オブジェクト指向プログラミングの核となる考え方は、次の箇条書きに要約できます。

  • データとそのデータに対して呼び出すことができる関数のコレクションである「クラス」を定義します。
  • これらの特定の関数は、その特定のクラスの「メソッド」と呼ばれます。
  • クラスの実際のインスタンスは「オブジェクト」と呼ばれます。

これら 3 つの概念を理解するために、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 の 4 つの柱について説明する必要があると思います。

継承

継承では、OOP の クラスと クラスの概念が導入されます。子クラスは親クラスから派生したクラスであり、そのすべてのメソッドとプロパティ (データ) を継承します。これを理解するのに役立つコードをいくつか見てみましょう:

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()
}

ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

この例では、バットマンとアイアンマンはヒーローの親クラスの子クラスです。これらは、親クラスのプロパティ (チーム) とそのメソッド (SayTeam) にアクセスできます。 b1 インスタンスと i1 インスタンスを宣言するときにわかるように、親クラスのプロパティと、それぞれのクラスの固有のプロパティを指定します。どちらも、親クラスで定義されている SayTeam メソッドを呼び出すことができます。ただし、それぞれに固有の個別のプロパティとメソッドもあります。

Golang は、合成を使用して (構造体内の構造体を使用して) 継承を実装します。 C や Java などの他の 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()
}

ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
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 パッケージでアクターと年を小文字で定義すると、それらを直接変更できないようになります。代わりに、main.go ファイルで見られるように、エクスポートされたメソッド (大文字で始まる) - GetActor、SetActor などを使用して、それらを取得して変更する必要があります。

これがカプセル化の意味です。データへの誤った変更を確実に防ぎ、その代わりにデータを安全に操作する方法を提供します。

異なる点の 1 つは、Batman クラスのすべてのメソッドで、前の例のように値レシーバー Batman の代わりにポインター レシーバー *Batman を使用していることです。これは、Set メソッドで元の構造体を変更できるようにするためです。また、Golang では、一部のメソッドでポインタ レシーバが必要な場合は、一貫性を保つためにすべてのメソッドでポインタ レシーバを使用することがベスト プラクティスです。そのため、Get メソッドは、元の構造体を変更していないにもかかわらず、ポインター レシーバーも使用しています。

また、もう 1 つ注意すべき点は、ポインター レシーバーを使用しているからといって、(&b1).GetActor を実行する必要はないということです。 Golang では、ポインター引数を持つ関数はポインターを受け取る必要がありますが、ポインター レシーバーを持つメソッドは値またはポインターをレシーバーとして受け取ることができます。

TL;DR: GetActor メソッドにはポインター レシーバーがあるため、Golang は自動的に b1.GetActor を (&b1).GetActor に変換しますが、GetActor が通常の関数であった場合には GetActor(b1) を GetActor(&b1) に変換しません。ポインタ引数。

ポリモーフィズムと抽象化

OOP の次の 2 つの柱は、コード サンプルが非常に似ているため、クラブ化できます。ポリモーフィズムとは、2 つの異なるクラスの 2 つの異なるオブジェクトを同じ共通スーパークラスのオブジェクトとして扱うことができるプログラミング手法を指します。つまり、2 つの異なるオブジェクトに対して、それらが同じクラスのオブジェクトであるかのように、同じ関数を呼び出すことができます。これにより、インターフェイスが関与していることがわかり始めるはずです :)

これをよりよく理解するために、いくつかのコードを見てみましょう:

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 オブジェクトの両方を渡すことができます。これが、子クラスが親クラスのメソッドにアクセスできる継承とどのように異なるのかを理解してください。この例では、子クラスと親クラスはありません (また、共有されるメソッドもありません)。代わりに、2 つの異なるオブジェクトが 関数 によって同じものとして扱われます。これはポリモーフィズムと呼ばれます。

さて、これも抽象化の一例として扱うことができます。名前が示すように、抽象化とは、実装の詳細を隠し、代わりに処理を行う関数だけを提供するプログラミング手法です。この例では、個々のヒーローのメソッドがどのように構成されているかを気にする必要はありません。ヒーローのいずれかのファイト機能を使用したい場合はいつでも、StartFight 機能を使用し続けることができます。このようにして、実装の詳細はユーザーから隠されたままとなり、重要な詳細のみが公開されます。

ここでポリモーフィズムに戻りますが、さらに 2 つの一般的な例があります。それらはメソッドのオーバーライドとオーバーロードです。

メソッドのオーバーライド

メソッドのオーバーライドとは、親クラスで定義されたメソッドの独自の実装を定義する子クラスを指します。この実装は、元の親クラスの実装の代わりに使用されるようになりました。先ほど継承に使用したコードを取り上げ、メソッドのオーバーライドでどのように見えるかを見てみましょう:

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 クラスのオブジェクトは、親 Hero クラスのメソッドではなく、独自の SayTeam メソッドを使用するようになりました。 Ironman クラスには独自の SayTeam メソッドがないため、そのオブジェクトは依然として親クラスのメソッドを使用します。これがメソッドのオーバーライドを意味し、子クラスが親クラスで定義されたメソッドを「オーバーライド」します。

メソッドのオーバーロード

これは、同じ関数が複数の異なる引数を取ることができることを指します。これらの引数は、数や型が異なる場合があります。 Golang は、これを実現する 2 つの方法を提供します。1 つは可変引数関数を使用する方法、もう 1 つはインターフェイスを使用する方法です。

理解を深めるのに役立つ両方のコードを見てみましょう:

可変引数関数の使用

// 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 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Golang vs. Python:パフォーマンスとスケーラビリティ Golang vs. Python:パフォーマンスとスケーラビリティ Apr 19, 2025 am 12:18 AM

Golangは、パフォーマンスとスケーラビリティの点でPythonよりも優れています。 1)Golangのコンピレーションタイプの特性と効率的な並行性モデルにより、高い並行性シナリオでうまく機能します。 2)Pythonは解釈された言語として、ゆっくりと実行されますが、Cythonなどのツールを介してパフォーマンスを最適化できます。

Golang and C:Concurrency vs. Raw Speed Golang and C:Concurrency vs. Raw Speed Apr 21, 2025 am 12:16 AM

Golangは並行性がCよりも優れていますが、Cは生の速度ではGolangよりも優れています。 1)Golangは、GoroutineとChannelを通じて効率的な並行性を達成します。これは、多数の同時タスクの処理に適しています。 2)Cコンパイラの最適化と標準ライブラリを介して、極端な最適化を必要とするアプリケーションに適したハードウェアに近い高性能を提供します。

Golangの影響:速度、効率、シンプルさ Golangの影響:速度、効率、シンプルさ Apr 14, 2025 am 12:11 AM

speed、効率、およびシンプル性をspeedsped.1)speed:gocompilesquilesquicklyandrunseffictient、理想的なlargeprojects.2)効率:等系dribribraryreducesexexternaldedenciess、開発効果を高める3)シンプルさ:

ゴーを始めましょう:初心者のガイド ゴーを始めましょう:初心者のガイド Apr 26, 2025 am 12:21 AM

goisidealforforbeginnersandsutable forcloudnetworkservicesduetoitssimplicity、andconcurrencyfeatures.1)installgofromtheofficialwebsiteandverify with'goversion'.2)

Golang vs. C:パフォーマンスと速度の比較 Golang vs. C:パフォーマンスと速度の比較 Apr 21, 2025 am 12:13 AM

Golangは迅速な発展と同時シナリオに適しており、Cは極端なパフォーマンスと低レベルの制御が必要なシナリオに適しています。 1)Golangは、ごみ収集と並行機関のメカニズムを通じてパフォーマンスを向上させ、高配列Webサービス開発に適しています。 2)Cは、手動のメモリ管理とコンパイラの最適化を通じて究極のパフォーマンスを実現し、埋め込みシステム開発に適しています。

Golang vs. Python:重要な違​​いと類似点 Golang vs. Python:重要な違​​いと類似点 Apr 17, 2025 am 12:15 AM

GolangとPythonにはそれぞれ独自の利点があります。Golangは高性能と同時プログラミングに適していますが、PythonはデータサイエンスとWeb開発に適しています。 Golangは同時性モデルと効率的なパフォーマンスで知られていますが、Pythonは簡潔な構文とリッチライブラリエコシステムで知られています。

GolangとC:パフォーマンスのトレードオフ GolangとC:パフォーマンスのトレードオフ Apr 17, 2025 am 12:18 AM

GolangとCのパフォーマンスの違いは、主にメモリ管理、コンピレーションの最適化、ランタイム効率に反映されています。 1)Golangのゴミ収集メカニズムは便利ですが、パフォーマンスに影響を与える可能性があります。

CとGolang:パフォーマンスが重要な場合 CとGolang:パフォーマンスが重要な場合 Apr 13, 2025 am 12:11 AM

Cは、ハードウェアリソースと高性能の最適化が必要なシナリオにより適していますが、Golangは迅速な開発と高い並行性処理が必要なシナリオにより適しています。 1.Cの利点は、ハードウェア特性と高い最適化機能に近いものにあります。これは、ゲーム開発などの高性能ニーズに適しています。 2.Golangの利点は、その簡潔な構文と自然な並行性サポートにあり、これは高い並行性サービス開発に適しています。

See all articles