5/16 ドメイン駆動設計Chapter5 テスト前まで
リポジトリとは何か
データの保管庫。
ドメインオブジェクト(値オブジェクト・エンティティ)とデータベースを直接やりとりせず、リポジトリを介して行う。
リポジトリのインターフェース
定義するものは、リポジトリの責務である、オブジェクトの永続化に関わるものだけです。
interface IUserRepository { save(user: User): void; find(name: UserName): User; }
- インターフェース(抽象型)なので実体は別のクラスで定義します
- saveメソッドとfindメソッドがあることがわかります。
- Chapter4で使ったexistsメソッド(重複チェック)はリポジトリに定義するべきか?
interface IUserRepository { save(user: User): void; find(name: UserName): User; exists(name: UserName): boolean; }
- ユーザ名で重複確認をするのであれば、Userを渡すのではなく、具体的なUserNameを引き渡す(ドメインサービスにインフラにまつわる処理を書きたくない場合)
まとめ
重複チェックメソッドの定義において、ドメインサービスにインフラにまつわる処理を書きたくないから、リポジトリに定義する場合。
ダメな例
interface IUserRepository { save(user: User): void; find(name: UserName): User; // 引数に具体的なキーのユーザ名ではなくUserとしている exists(name: User): boolean; } class UserService { constructor(private readonly user: User, private readonly userRepository: IUserRepository) {} public exists(user: User): boolean { // ドメインサービスがユーザ名により重複確認するという知識が失われている return this.userRepository.exists(this.user); } }
良い例
interface IUserRepository { save(user: User): void; find(name: UserName): User; // 重複チェックの具体的なキーであるユーザ名UserNameを引数としている exists(name: UserName): boolean; } class UserService { constructor(private readonly userName: UserName, private readonly userRepository: IUserRepository) {} public exists(user: User): boolean { // ドメインサービスでユーザ名で重複チェックを行うのだと見ればわかる return this.userRepository.exists(this.userName); } }
リポジトリの実体のクラスを作成
インターフェース(抽象型)で定義した実体です(existsは省きます)
例としてORMはPrismaを使ったと仮定したもの(Prismaのimport分等省きます)
//インターフェース interface IUserRepository { save(user: User): void; find(name: UserName): User; } //ここからリポジトリの実体 class UserRepository implements IUserRepository { private prisma: PrismaClient; constructor(prisma: PrismaClient) { this.prisma = prisma; } async save(user: User): Promise<void> { const { id, name } = user; await this.prisma.user.create({ data: { id: id, name: name, }, }); } async find(name: UserName): Promise<User | null> { const user = await this.prisma.user.findUnique({ where: { name: name, }, }); return user ? new User(user.id, user.name) : null; } }
- saveメソッドとfindメソッドの内容がここで実装されています
- implementsでIUserRepositoryを部分型としているのでsave・findメソッドが定義されていないとコンパイルエラーになる