2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【備忘録】結局Interactorってなんだ。なんでユースケースがInteractorを介して実行されるんだ

2
Last updated at Posted at 2025-07-16

クリーンアーキテクチャを学んでいると、UseCaseという名前ではなく Interactor という少し見慣れないオブジェクトに出会うことがある。この記事では、Interactorがなぜ使われるのか、その役割とメリットを解説する。

この記事のギモン
なぜ usecase.NewCreateAccountUseCase ではなく usecase.NewCreateAccountInteractor なのか? Interactor の正体とは?

なぜInteractorが必要なのか?

結論から言うと、Interactorは仲介役という単語自体の意味から予想される通り、 「UseCaseの具体的な実装を担当する仲介役」 である。

クリーンアーキテクチャでは、関心事の分離が重要視される。特に、アプリケーションの核となるビジネスルールを定義するUseCaseは、できるだけシンプルに保ちたいという思想がある。

理想的なUseCaseのインターフェースは、次のように「何をするか」だけを定義する。

// 「アカウントを作成する」というビジネスルールそのものを定義
type CreateAccountUseCase interface {
    Execute(context.Context, CreateAccountInput) (CreateAccountOutput, error)
}

このUseCaseは「実行(Execute)できる」ことだけが分かればよく、余計な情報を持つべきではない。

しかし、実際の処理ではデータベースとやり取りするためのリポジトリや、結果を整形して返すためのプレゼンターといった依存オブジェクトが不可欠だ。

ここでInteractorが登場する。

Interactorは、これらの依存オブジェクトをすべて保持し、UseCaseインターフェースを実装することで、 ビジネスルールの純粋さを保ちつつ、具体的な処理を実現する という役割を担う。

ドメインオブジェクト,リポジトリ,プレゼンターを使用してUseCaseインターフェースを実装している様子が以下の図からよくわかる。
image.png

コードで見るInteractorの仕組み

Interactorがどのように機能するのか、コードを追いながら見ていこう。

1. Interactorの構造

Interactorは、処理に必要な依存オブジェクトをフィールドとして保持するstruct(構造体)として定義される。

// 依存オブジェクト(リポジトリ、プレゼンター等)を保持する仲介役
type createAccountInteractor struct {
    repo       domain.AccountRepository // DB操作を担当
    presenter  CreateAccountPresenter // 出力整形を担当
    ctxTimeout time.Duration
}

2. UseCaseインターフェースの実装

次に、このInteractorUseCaseインターフェースのExecuteメソッドを実装する。これにより、InteractorUseCaseとして振る舞えるようになる。

// createAccountInteractorがExecuteメソッドを持つ
func (a createAccountInteractor) Execute(ctx context.Context, input CreateAccountInput) (CreateAccountOutput, error) {
    // ... アカウント作成のロジック ...

    // 保持しているリポジトリを使ってDBに保存
    account, err := a.repo.Create(ctx, account)
    if err != nil {
        return a.presenter.Output(domain.Account{}), err
    }

    // 保持しているプレゼンターを使って出力
    return a.presenter.Output(account), nil
}

ポイントは、Interactorが内部にrepopresenterを持っているため、Executeメソッド内でそれらを利用できる点だ。

3. Interactorの生成と利用

最後に、Interactorを生成する関数だ。この関数は、必要な依存関係(repopresenter)を受け取り、Interactorのインスタンスを生成して返す。

重要なのは、戻り値の型がcreateAccountInteractorという具体的な型ではなく、CreateAccountUseCaseというインターフェースになっている点だ。

// Interactorを生成し、「UseCase」として返す
func NewCreateAccountInteractor(
    repo domain.AccountRepository,
    presenter CreateAccountPresenter,
    t time.Duration,
) CreateAccountUseCase { // 戻り値はインターフェース型
    return createAccountInteractor{
        repo:       repo,
        presenter:  presenter,
        ctxTimeout: t,
    }
}

これにより、呼び出し側はInteractorという具体的な実装を意識することなく、「CreateAccountUseCaseというビジネスルールを実行するオブジェクト」として扱うことができる。

結論

Interactorは、クリーンアーキテクチャにおいて非常に重要な役割を果たす。

  • UseCase (インターフェース)

    • 役割: アプリケーションのビジネスルール(契約)を定義する。
    • 特徴: 「何をするか」だけを規定し、シンプルに保つ。
  • Interactor (構造体)

    • 役割: UseCaseインターフェースの具体的な実装。リポジトリやプレゼンターといった依存関係をまとめる「仲介役」であり「実行役」。
    • 特徴: 「どうやってやるか」を担当する。

このように役割を分離することで、ビジネスロジックと具体的な実装の詳細が切り離され、変更に強く、テストしやすい、クリーンなアーキテクチャが実現できるのだ。

参考リポジトリ

2
1
0

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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?