りゅうじの学習blog

学習したことをアウトプットしていきます。

5/24 ドメイン駆動設計 Chapter7 7-2

7-2依存とは

依存は、あるオブジェクトがあるオブジェクトを参照するだけで発生します。

class ObjectA {
  constructor(private objectB: ObjectB) {}
}
  • ObjectAはObjectBを参照しています
    • ObjectBの定義が存在しない限りObjectAも成り立ちません
      • ObjectAはObjectBに依存していると言えます

依存関係は図で表すことができる

  • 依存は依存する側のモジュールから依存される側のモジュールへと矢印を伸ばして表現する

依存関係は参照のみではなく、インターフェースとその実体になる実装クラスの関係でも発生します。

interface IUserRepository {
  save(user: User): void;
  find(id: UserId): Promise<User | null>;
}
class UserRepository implements IUserRepository {
  constructor(private prisma: PrismaClient) {}

  async save(user: User): Promise<void> {
    const { id, name } = user;
    await this.prisma.user.create({
      data: {
        id: id,
        name: name,
      },
    });
  }

  async find(id: UserId): Promise<User | null> {
    const user = await this.prisma.user.findUnique({
      where: {
        id: id,
      },
    });
    return user ? new User(user.id, user.name) : null;
  }
}
  • UserRepositoryクラスはIUserRepositoryインターフェースを実装しています
    • IUserRepositoryの定義が存在しなかったとしたらクラスの宣言部でコンパイルエラーになりUserRepositoryが成り立ちません
      • UserRepositoryはIUserRepositoryに依存していることになる

class UserApplicationService {
  constructor(private readonly userRepository: UserRepository) {}
  // 省略
 }
  • UserApplicationServiceにはUserRepositoryがフィールドとして定義されている
    • UserApplicationServiceはUserRepositoryに依存している状態です

  • これは5章でやったように、実体クラスをそのまま使うのではなく、インターフェースを介してUserRepositoryを利用するのがいいです
class UserApplicationService {
  constructor(private readonly userRepository: IUserRepository, private readonly userService: UserService) {}
// 省略
}
  • IUserRepositoryを受け取るようにする
    • IUserRepositoryを実装した実体クラスであれば、その実体が何であっても引き渡すことができるようになります
      • 特定のデータストアにUserApplicationクラスが結びつく必要がなくなりました
        • インメモリで動作するテスト用のリポジトリを引き渡してユニットテストもできます
        • 別のデータストアを利用するリポジトリを作って、主のロジックの変更をしなくてもデータストアを差し替えることも可能です

  • 抽象型を利用すると、具象型に向いていた依存の矢印が抽象型に向くようになります
  • 依存の方向性を、すべてのモジュールが抽象へ依存するように制御することは、ビジネスロジックを具体的な実装から解き放ち、より純粋なものに昇華する効果があります

この抽象型を用いた依存関係の制御を依存関係逆転の原則といいます。

参考

ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本