LoginSignup
59
55

More than 3 years have passed since last update.

オブジェクト指向な人に捧ぐGO言語の特徴

Last updated at Posted at 2019-11-02

TL;DR

GO言語はOOP(オブジェクト指向)な思考回路で書くと割ととっちらかってしまうので、特徴的なところをピンポイントで抑えたいとおもいます。

多態性(ポリモーフィズム)はダックタイピングで実現

宣言的に親(あるいはインターフェイス)を記述しなくても、そのオブジェクトが実装条件を満たしていれば親(インターフェイス)として振舞うことができます。

こちらがインターフェイス。


type Hito interface {
    walk() string
}

Hitoインターフェイスを満たすにはstructがwalk()を持つように実装します。Maleというstructを実装してみました。


type Male struct {
}

func (m Male) walk() string {
    return "テクテク"
}

MaleHitoインターフェイスを満たしているのでdoWalk(h Hito)に引数として渡せるようになります。


func main() {
    male := Male{}
    doWalk(male)
}

func doWalk(h Hito) {
    fmt.Println(h.walk())
}

使いどころとしてはモックを作成するようなシチュエーションです。
doWalk()に渡すオブジェクトはwalk()を持っていればなんでも渡せることになり、いちいちインターフェイスを実装してることを明示しなくていいので楽ちんです。

Playgroundを共有しておくので実際に動かしてみてください。
https://play.golang.org/p/drJt13gSyWw

Is-aではなくHas-a

GO言語の特徴として継承(Is-a)という概念がなく、すべて包含(Has-a)で記述します。継承っぽく書くには書けるのですが、それっぽく見えているだけで実際は包含しているオブジェクトにアクセスする形になります。

先ほどのMaleを流用します。

type Male struct {
}

func (m Male) walk() string {
    return "テクテク"
}

次にMaleを包含したAdultMaleを作ります。

type AdultMale struct {
    Male
}

AdultMaleは明示的にwalk()を実装しているわけではありませんが、walk()をコールすると包含しているMalewalk()がコールされることになります。


func main() {
    adultMale := AdultMale{}
    fmt.Println(adultMale.walk())    // テクテク
}

もしAdultMaleでwalk()を再定義してやればそちらがコールされます。

type AdultMale struct {
    Male
}

func (a AdultMale) walk() string {
    return "ドカドカ"
}

func main() {
    adultMale := AdultMale{}
    fmt.Println(adultMale.walk())    // ドカドカ
}

こちらもplaygroundを載せておきますのでいじってみてください。
https://play.golang.org/p/OvdKcT22bbx

ダックタイピングとHas-aの合わせ技

ここからGOの便利さが実感できるコードを書きます。
こちらは先ほどのHitoさん。

type Hito interface {
    walk() string
}

道路を表すRoadを作りました。道路を歩くHitoさんがいます。

type Road struct {
    Hito
}

func (r Road) doWalk() {
    fmt.Println(r.walk())
}

このようにRoadを定義しておけばどのように道路を歩くかを作成する側で決めることができます。DIするようなシチュエーションで強力です。(Male{}、Female{}を作る部分をFactoryに切り出すなど)

type Male struct {
}

func (m Male) walk() string {
    return "テクテク"
}

type Female struct {
}

func (f Female) walk() string {
    return "シトシト"
}

func main() {
    Road{Male{}}.doWalk()    // テクテク
    Road{Female{}}.doWalk()  // シトシト
}

こちらもplaygroundを載せておきます。
https://play.golang.org/p/jAXcF08ZWni

ちょっと長くなってしまったのでいったんこの辺で。
またエラーハンドリング周りも特徴的なのでその辺を次回に書きたいと思います。

59
55
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
59
55