無気力生活 (ノ ´ω`)ノ ~゜

脱力系エンジニア。てきとーに生きてます。

golangでoverrideを実現するためには

golangは継承がない言語ではありますが、メソッドのオーバーライドを行うことができます。

qiita.com

embedded使います。 本来はinterface定義して解決した方がいいんですけども、使っているパッケージでinterface定義されていないやつのMock作るとき等、これで解決しないといけなさそうなケースがありました(´・ω・`)

// embeddedされる側
type BaseModel struct {
    Name string
}
func (b *BaseModel) Talk() string {
    return fmt.Sprintf("name is %s", b.Name)
}
func (b *BaseModel) Action(in string) string {
    return fmt.Sprintf("%s, actively %s.", b.Talk(), in)
}
func NewBaseModel(name string) *BaseModel {
    return &BaseModel{
        Name: name,
    }
}

// embeddedする側
type ModelA struct {
    BaseModel
    ActionName string
}
// Actionだけ定義してBase側を上書きする
func (m *ModelA) Action(in string) string {
    return fmt.Sprintf("%s, %s %s.", m.Talk(), m.ActionName, in)
}
func NewModelA(name, action string) *ModelA {
    model := &ModelA{
        BaseModel:  *NewBaseModel(name),
        ActionName: action,
    }
    return model
}

な定義があったとして、

package main

import "fmt"

func main() {
    dog := NewBaseModel("bog")
    fmt.Println(dog.Action("run"))

    cat := NewModelA("cat", "selfishness")
    fmt.Println(cat.Action("run"))
}

で動かす。

name is bog, actively run.
name is cat, selfishness run.

期待通りの動作はする。うーん、単純なものならこれで動くのか。

例えば、外部にリクエスト投げるモジュールがあったとして、そいつの送信部分だけ外部に送らないようにする処理で上書きしてやれば、Mock化が簡単にできそうな気がします。

ただ、上記で上書きしきれないパターンがある

今仕事でやってるFirestoreの実送信部分。上書きしたはずが、上書き元が呼ばれてしまうんですよね。

直接オブジェクト作ったところで呼ぶ分には期待通り動きそうですが、メソッドのレシーバーでembedded元が指定されているとそっち呼んでしまうのかな(´・ω・`)あとで検証しますか

多分この[メソッド定義とメソッド呼び出しの真実]あたりが、embedded側が呼ばれる原因なのかもしれません。

skatsuta.github.io