4

DDD を使用してアプリを構築していますが、仕様クラスをインスタンス化する場所や使用する場所を理解するのに苦労しています。

私のアプリは予約期間を多用するため、集計に追加されようとしている予約期間が、現在集計内にある別の期間と重ならないようにする仕様を持っています。以下のように。

    /// <summary>
/// A specification that determines if the window passed in collides with other windows.
/// </summary>
public class BookingTemplateWindowDoesNotCollideSpecification : ISpecification<BookingScheduleTemplateWindow>
{
    /// <summary>
    /// The other windows to check the passed in window against.
    /// </summary>
    private readonly IEnumerable<BookingScheduleTemplateWindow> otherWindows;

    /// <summary>
    /// Initializes a new instance of the <see cref="BookingTemplateWindowDoesNotCollideSpecification" /> class.
    /// </summary>
    /// <param name="otherWindows">The other windows.</param>
    public BookingTemplateWindowDoesNotCollideSpecification(IEnumerable<BookingScheduleTemplateWindow> otherWindows)
    {
        this.otherWindows = otherWindows;
    }

    /// <summary>
    /// Determines whether the window passed in collides with other windows held inside this class.
    /// </summary>
    /// <param name="obj">The obj.</param>
    /// <returns>
    ///  <c>true</c> if [is satisfied by] [the specified obj]; otherwise, <c>false</c>.
    /// </returns>
    public bool IsSatisfiedBy(BookingScheduleTemplateWindow obj)
    {
        return !this.otherWindows.Any(w => obj.DayOfWeek == w.DayOfWeek && w.WindowPeriod.IsOverlap(obj.WindowPeriod));
    }
}

そして、仕様を使用して新しいウィンドウを追加できるようにするメソッドが集計にありました。既に永続化されたウィンドウの集約は、仕様コンストラクターに渡されます。

        public virtual void AddWindow(DayOfWeek dayOfWeek, int startTime, int endTime)
    {
        var nonCollidingWindowSpecification = new BookingTemplateWindowDoesNotCollideSpecification(this.Windows);
        var bookingWindow = new BookingScheduleTemplateWindow(this){
                                                                       DayOfWeek = dayOfWeek,
                                                                       WindowPeriod = new Range<int>(startTime, endTime)
                                                                   };

        if (nonCollidingWindowSpecification.IsSatisfiedBy(bookingWindow))
        {
            this.Windows.Add(bookingWindow);
        }
    }

私が苦労しているのは、仕様のタイプが必要になる可能性があるため、(この場合だけでなく、一般的なルールとしてアプリ全体で) 直接インスタンス化するのではなく、この仕様をクラスに注入する必要があると考えていることです。エンティティの状態に応じて変更します。しかし、REST API のような別のアプリケーション インターフェイスがあるかのように、MVC レイヤーから仕様を注入するのは汚いと感じ、使用する仕様についてのロジックが複製されます。

どの仕様を使用するかについてのロジックが別のアプリケーション インターフェイスで重複しないようにしながら、使用されている仕様の柔軟性を維持するにはどうすればよいでしょうか。

これは、ファクトリをエンティティに挿入し、そこから仕様を返したい場合で、ドメイン ロジックが上位層に流出しないようにする場合ですか? または、これを行うためのより良い/よりクリーンな/より簡単な方法はありますか?

4

1 に答える 1

2

ドメインサービスをエンティティに注入することは完全に許容されます。アグリゲートのそれぞれのメソッドのパラメーターとして、サービスへの依存関係を明示的にするのが最善です。たとえば、AddWindowメソッドは次のようになります。

  public virtual void AddWindow(ISpecification<BookingScheduleTemplateWindow> nonCollidingWindowSpecification, DayOfWeek dayOfWeek, int startTime, int endTime)
  {
        var bookingWindow = new BookingScheduleTemplateWindow(this){
                                                                       DayOfWeek = dayOfWeek,
                                                                       WindowPeriod = new Range<int>(startTime, endTime)
                                                                   };

        if (nonCollidingWindowSpecification.IsSatisfiedBy(bookingWindow))
        {
            this.Windows.Add(bookingWindow);
        }
    }

この場合、仕様はドメインサービスとして機能します。現在、適切な仕様に合格するかどうかは、周囲のインフラストラクチャ次第です。これがアプリケーションサービスの出番です。アプリケーションサービスは、ドメインレイヤー上にファサードを確立し、特定のユースケースのメソッドを含みます。このアプリケーションサービスは、コントローラーによって参照されます。コントローラに必要な依存関係を渡させることも可能ですが、アプリケーションサービスによって提供されるカプセル化が有益な場合があります。

サンプルアプリケーションサービスコード:

public class AddWindow(string aggregateId, DayOfWeek dayOfWeek, int startTime, int endTime)
{
    var aggregate = this.repository.Get(aggregateId);
    var specification = // instantiate specification
    aggregate.AddWindow(specification, dayOfWeek, startTime, endTime);
    this.repository.Commit();
}

これは典型的なアプリケーションサービスコードです。適切なアグリゲートを取得し、必要な依存関係がある場合はそれをインスタンス化し、アグリゲートで動作を呼び出します。

于 2012-12-05T15:47:27.307 に答える