永続指向のリポジトリ
最後に「永続指向のリポジトリ」のコードについて紹介します。先ほど紹介した通り、永続指向は対象ストレージがNoSQLなどのキーバーリューストアの時に使用し、集約の情報全体をまとめて保存します。インターフェイス(Java/C#)は次の通りです。
// ■プロダクト集約を管理するリポジトリ
public interface ProductRepository {
// ▼プロダクト集約を取得(テナントID+プロダクトID)
public Product productOfId(TenantId aTenantId, ProductId aProductId);
// ▼リポジトリに保存
public void save(Product aProduct);
// ▼リポジトリから削除
public void remove(Product aProduct);
~中略~
}
集約全体をMongoDBやLevelDBの1つのレコード(ドキュメント)として保存するため、AddメソッドではなくSaveメソッドを使います。それ以外はコレクション指向のインターフェイス設計と同じです。
永続指向のリポジトリ実装クラス
続けて、実装クラスのコード(Java)を見てみましょう。ここではNoSQLのひとつであるLevelDBによる実装となっています。
// ■LevelDBでの実装リポジトリ
public class LevelDBProductRepository
extends AbstractLevelDBRepository implements ProductRepository {
private static final String PRIMARY = "PRODUCT#PK";
// ▼コンストラクタで、DBの場所として、コンテキスト名を使用
public LevelDBProductRepository() {
super(LevelDBDatabasePath.agilePMPath());
}
// ▼プロダクト集約を取得(テナントID+プロダクトID)
@Override
public Product productOfId(TenantId aTenantId, ProductId aProductId) {
// 取得に使うキーを設定する
LevelDBKey primaryKey =
new LevelDBKey(PRIMARY, aTenantId.id(), aProductId.id());
Product product =
LevelDBUnitOfWork.readOnly(this.database())
.readObject(primaryKey.key().getBytes(), Product.class);
return product;
}
// ▼プロダクトをリポジトリに保存
@Override
public void save(Product aProduct) {
LevelDBKey lockKey = new LevelDBKey(PRIMARY, aProduct.tenantId().id());
LevelDBUnitOfWork uow = LevelDBUnitOfWork.current();
uow.lock(lockKey.key());
this.save(aProduct, uow);
}
~中略~
}
ここではLevelDBに対する保存/削除/取得処理を記述しています。NoSQLでは、データの格納と取得のために一意なキーの設計が必要です。IDDD本では「境界づけられたコンテキストの短縮名」「集約の名前」「一意な識別子」を組み合わせる案を提示しています。
このプロダクトという集約の例であれば、まずDBそのものをコンテキスト名(LevelDBDatabasePath.agilePMPathの部分)にて分離し、それ以外の集約を示す定数「PRODUCT#PK」と一意な識別子「テナントID」+「プロダクトID」の組み合わせをキーとして使用しています。
以上、永続指向によるリポジトリの実装方法について紹介しました。
最後に
本稿ではDDDにおけるリポジトリについて紹介しました。集約の永続化を管理するにあたって、いくつかの設計指針、実装パターンがあることが理解できたと思います。次回の第13回では「境界づけられたコンテキストの結合」について紹介します。
