貧血ドメインからドメイン推進者へ
-
21-12-2019 - |
質問
私は貧血のあるドメインが本当に意味するものの明確で簡単な例を見つけようとしていました。周りにはたくさんの理論があり、また多くのよく答えられた質問があります。それでも、私はどの程度「貧血ドメイン」という意味が本当に行くことを明確にすることはできませんでした。したがって、貧血ドメインデザインのダミーの実用的な例を見ることがより簡単であり、あなたにこれをドメイン駆動されるものにどのように進化させることができるよりも簡単であると思います...
それで、 taskData :
のデータエンティティを持っているとしましょう。public class TaskData
{
public Guid InternalId { get; set; }
public string Title { get; set; }
public string Details { get; set; }
public TaskState ExplicitState { get; set; }
public IEnumerable<TaskData> InnerTasks { get; set; }
}
.
と計算された状態である " actualstate "という追加のプロパティが必要です。タスクに内部サブタスクがある場合、その値は厳密に子供たちから異なります。 " actualState "は " ExplicitState "
に等しいです。このロジックを別のサービスクラスに書き込む場合(私はそれらを「エンジン」と呼びます)我々は持っています:
internal class TaskStateCalculator
{
public TaskState GetState(TaskData taskData)
{
if (taskData.InnerTasks.Any())
{
if (taskData.InnerTasks.All(x => this.GetState(x) == TaskState.Done))
{
return TaskState.Done;
}
if (taskData.InnerTasks.Any(x => this.GetState(x) == TaskState.InProgress))
{
return TaskState.InProgress;
}
return TaskState.Default;
}
return taskData.ExplicitState;
}
}
.
最初の質問は次のとおりです。
taskstateCalculator サービス/エンジンがドメイン層の一部であっても、上記のコードは貧血ドメイン設計を反映していますか? そうであれば、それを回避するためには、 taskdata クラス内のロジックを移動する必要があります(そして taskData をタスクに変更します)。私は正しいですか?
2番目の質問は(実際にはそれらのチェーン):
私たちがより困難な状況を持っているならばどうなりますか? タスクエンティティ内で computesomething というプロパティが必要であり、このプロパティのロジックはタスクの repository にアクセスする必要があります。この場合、タスククラスは taskrepository に依存します。これは大丈夫だろうか? EFはそのようなクラスのインスタンスを構築するのでしょうか。代替案は何ですか?
解決
私は貧血のあるドメインが本当に
を意味するものの明確で簡単な例を見つけようとしていました
実際には貧血のあるドメインモデルから豊かなものへ行くのが本当に簡単です。
- すべてのプロパティセチターを
private
に設定し、モデルの状態を変更したい場合はメソッドを追加します。 - すべての Demeter 違反の法則と適切な方法を追加します。
最終的には正しいモデルがあります。
あなたの場合は、TaskStateCalculatorがdemeter
の法則に違反しているため、TaskData
の中のそのロジックをカプセル化するでしょう。
public class TaskData
{
public Guid InternalId { get; private set; }
public string Title { get; private set; }
public string Details { get; private set; }
public TaskState ExplicitState { get; private set; }
public IEnumerable<TaskData> InnerTasks { get; private set; }
public TaskState GetState()
{
if (!InnerTasks.Any())
return ExplicitState;
if (InnerTasks.All(x => this.GetState(x) == TaskState.Done))
{
return TaskState.Done;
}
if (InnerTasks.Any(x => this.GetState(x) == TaskState.InProgress))
{
return TaskState.InProgress;
}
return TaskState.Default;
}
}
.
もう一つのことは、私がおそらくinnertasksコレクションを外の世界に公開しないでしょう(単にそれをメンバーフィールドとして持っています)。しかし、私が他のシナリオでどのように使用されているかわからないので言うのは難しいです。
なぜプライベートセッター
複数のプロパティを変更するたびに、必要なプロパティをすべて変更することを忘れることは不可能な方法で行動を説明することが多いことがよくあります。方法はまた、一連のプロパティを変更するよりもやろうとしていることをよりよく説明します。
単一のプロパティを変更しても、そのプロパティはクラス内の残りの情報との残りの情報と互換性がない場合があるため、そのプロパティはクラスを無効な状態に設定できます。カプセル化がOOP
の中核原理の1つであることを忘れないでください