前回はオブジェクト指向の自動化というお話をしました。データベースの列をValueObjectにして,行をEntityにしましょうというお話でした。Repositoryに関しては,外部接触部分をインタフェース化するという事でしたが,Repositoryの具象クラスを作るという考え方もあります。
Repositoryの具象クラスにするケース
データベースから取得した値を,そのままEntityに格納して,ViewModelで使用するだけの場合は具象クラスにする必要はないのですが,例えばデータベースから取得した値を,加工してEntityに入れたい場合などは,Infrastructure層で加工せず,Repositoryの具象クラスで加工したほうがいいです。
Infrastructure層で加工しないほうがいい理由
Infrastructure層で加工しないほうがいい理由は,単純に「テストコードが書き辛い」からです。
Infrastructure層では,実際のSqlServerに接触するため,テストコードからはMoqでタミーの値を流し込みます。なので,Infrastructure層はできるだけシンプルにしておいたほうがいいのです。SQLが複雑であればあるほど,テストコードでテストされていない部分が増えてしまうので,可能な限りSQLはシンプルに実装したほうがいいです。
SQLで取得した値をC#で加工したほうが,融通がきくし,テストコードにかけれるので,バグりにくいプログラムになります。
ViewModelで加工しないほうがいい理由
データベースから取得した値をViewModelで加工してしまうと,画面単位で実装する必要が出てきます。そうなると,ビジネスロジックが各画面にちらばってしまいます。ビジネスロジックはドメイン層に置いておき,だれでも使いたい人が使える状態にしておくのがいい実装です。なので,ViewModelでの加工も極力行わないほうがいいのです。
ドメイン層で加工する方法
以上の理由から,ドメイン層で加工するのがいいのですが,それをどこでするのがいいのか?というお話です。1つの選択しとしてはRepositoryの具象クラスを作るという試みです。例えばIMeasureRepository経由で取得した後に,何か加工したい場合は,MeasureRepositoryという名前のクラスを作ります。
MeasureRepositoryの作成
Domain層のRepositoriesフォルダーを右クリックして,「追加」「クラス」の順で選択し,MeasureRepositoryクラスを作成します。
頭に「I」のついていない,普通のクラスを作ります。
MeasureRepositoryのコーディング
次のように実装します。
using NDDD.Domain.Entities; namespace NDDD.Domain.Ripositories { public sealed class MeasureRepository { private IMeasureRepository _repository; public MeasureRepository(IMeasureRepository repository) { _repository = repository; } public MeasureEntity GetLatest() { var val1 = _repository.GetLatest(); System.Threading.Thread.Sleep(1000); var val2 = _repository.GetLatest(); System.Threading.Thread.Sleep(1000); var val3 = _repository.GetLatest(); System.Threading.Thread.Sleep(1000); var val = (val1.MeasureValue.Value + val2.MeasureValue.Value + val3.MeasureValue.Value) / 3; return new MeasureEntity(val3.AreaId.Value, val3.MeasureDate.Value, val); } } }
IMeasureRepositoryを宣言し,コンストラクタでIMeasureRepositoryを設定します。このクラスの中で,IMeasureRepositoryのGetLatestを呼び出し,好きなように加工します。このようにすると,テストコードにかけることができます。今回の例では,GetLatestを3回呼び出して,平均を取得するという処理です。このような処理はSQLでやろうとすると難しい処理です。SQLではあまり無理せず,C#で加工したほうがいいです。
ViewModelの変更
MeasureRepositoryを具象クラスにしたので,LatestViewModelは次のように変更します。
using NDDD.Domain.Entities; using NDDD.Domain.Ripositories; using NDDD.Infrastructure; using System; using System.ComponentModel; namespace NDDD.WinForm.ViewModels { public class LatestViewModel : ViewModelBase { //private IMeasureRepository _measureRepository; private MeasureRepository _measureRepository; private string _areaIdText = string.Empty; private string _measureDateText = string.Empty; private string _measureValueText = string.Empty; public LatestViewModel() : this(Factories.CreateMeasure()) { } public LatestViewModel(IMeasureRepository measureRepository) { _measureRepository = new MeasureRepository(measureRepository); } (省略) public void Search() { var measure = _measureRepository.GetLatest(); AreaIdText = measure.AreaId.DisplayValue; MeasureDateText = measure.MeasureDate.DisplayValue; MeasureValueText = measure.MeasureValue.DisplayValue; } } }
IMeasureRepositoryを宣言していた部分をMeasureRepositoryに変更し,コンストラクタでは,引数のIMeasureRepositoryを利用してMeasureRepositoryを生成しています。 SearchメソッドのGetLatestは具象クラスのGetLatestが呼び出されるので,加工された値(3回取得した平均の値)が取得できます。 これで,データベースからの値取得後のビジネスロジックを共通化できます。