Goのインターフェースの話

インターフェースを返すコードが間違っているという記事を見た。

オレの書くGoは間違っていた

私も大体同じような実装をしていた。もともとは誰かが公開していたソースコードを真似して書いていたと思う。
違ったのは「おまじない」の部分を書いていないことだけだ。

しかしmattnさんのツイートによると、上記記事が参照しているのは決して全Goユーザーへ向けたレビューポイントではないらしい。

そのためインターフェースを返す実装は間違っているわけではない。以上。


ただ私の実装は「何のためにインターフェースを書いているのかな……」と思うことがあって、どちらかというと使う側でインターフェースを定義するほうがしっくり来たので、インターフェースは使う側で定義するように修正してみた。

今までの実装

package producer

import "database/sql"

type IProducerRepository interface {
	Count() (int, error)
}

type ProducerRepository struct {
	*sql.DB
}

func NewProducerRepository(db *sql.DB) IProducerRepository {
	return &ProducerRepository{db}
}
package consumer

import "gitlab.com/k1350/sololog_gql/internal/repository/producer"

type ConsumerUsecase struct {
	producerRepository    producer.IProducerRepository
}

func NewConsumerUsecase(ur producer.IProducerRepository) *ConsumerUsecase {
	return &ConsumerUsecase{producerRepository: ur}
}

インターフェースは使う側で定義する実装

package producer

import "database/sql"

type ProducerRepository struct {
	*sql.DB
}

// 戻り値はインターフェースではない
func NewProducerRepository(db *sql.DB) *ProducerRepository {
	return &ProducerRepository{db}
}
package consumer

// インターフェースは使う側で定義する
type IProducerRepository interface {
	Count() (int, error)
}

type ConsumerUsecase struct {
	producerRepository    IProducerRepository
}

func NewConsumerUsecase(ur IProducerRepository) *ConsumerUsecase {
	return &ConsumerUsecase{producerRepository: ur}
}

なお『オレの書くGoは間違っていた』の記事だとDIツールを使っているのだが、別に使わなくても *ProducerRepositoryIProducerRepository を引数として受け入れる関数に渡せるので、元筆者の方がどういう意図でDIツールを使っていたのかはわからなかった。

以上