ドメイン駆動開発_フォルダー構成編_#43_Repositoryの具象クラス

当サイトではアフィリエイト広告を利用しています。

NDDD

前回はオブジェクト指向の自動化というお話をしました。データベースの列を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回取得した平均の値)が取得できます。 これで,データベースからの値取得後のビジネスロジックを共通化できます。