TL;DR
GO言語はOOP(オブジェクト指向)な思考回路で書くと割ととっちらかってしまうので、特徴的なところをピンポイントで抑えたいとおもいます。
多態性(ポリモーフィズム)はダックタイピングで実現
宣言的に親(あるいはインターフェイス)を記述しなくても、そのオブジェクトが実装条件を満たしていれば親(インターフェイス)として振舞うことができます。
こちらがインターフェイス。
type Hito interface {
walk() string
}
Hito
インターフェイスを満たすにはstructがwalk()
を持つように実装します。Male
というstructを実装してみました。
type Male struct {
}
func (m Male) walk() string {
return "テクテク"
}
Male
はHito
インターフェイスを満たしているので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()
をコールすると包含しているMale
のwalk()
がコールされることになります。
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
ちょっと長くなってしまったのでいったんこの辺で。
またエラーハンドリング周りも特徴的なのでその辺を次回に書きたいと思います。