Ich betrachte mich nicht als DDD-Experte, sondern versuche als Lösungsarchitekt, wenn immer möglich, Best Practices anzuwenden. Ich weiß, dass es eine Menge Diskussionen um die Vor- und Nachteile des No-Setter-Stils in DDD gibt, und ich kann beide Seiten des Arguments sehen. Mein Problem ist, dass ich in einem Team mit einer großen Vielfalt an Fähigkeiten, Kenntnissen und Erfahrungen arbeite, was bedeutet, dass ich nicht darauf vertrauen kann, dass jeder Entwickler die Dinge "richtig" macht. Wenn zum Beispiel unsere Domänenobjekte so konzipiert sind, dass Änderungen am internen Status des Objekts von einer Methode durchgeführt werden, die jedoch öffentliche Eigenschaftssetzer bereitstellt, wird die Eigenschaft unvermeidlich festgelegt, anstatt die Methode aufzurufen. Verwenden Sie dieses Beispiel:
public class MyClass
{
public Boolean IsPublished
{
get { return PublishDate != null; }
}
public DateTime? PublishDate { get; set; }
public void Publish()
{
if (IsPublished)
throw new InvalidOperationException("Already published.");
PublishDate = DateTime.Today;
Raise(new PublishedEvent());
}
}
Meine Lösung bestand darin, Eigenschaftssetzer privat zu machen, was möglich ist, da der ORM, den wir zum Hydratisieren der Objekte verwenden, Reflexion verwendet, um auf private Setzer zugreifen zu können. Dies stellt jedoch ein Problem dar, wenn versucht wird, Komponententests zu schreiben. Wenn ich zum Beispiel einen Komponententest schreiben möchte, der bestätigt, dass das Objekt nicht erneut veröffentlicht werden kann, muss ich darauf hinweisen, dass es bereits veröffentlicht wurde. Ich kann dies sicherlich tun, indem ich Publish zweimal aufrufe, aber mein Test geht dann davon aus, dass Publish beim ersten Aufruf korrekt implementiert ist. Das scheint ein wenig zu stinken.
Lassen Sie uns das Szenario mit folgendem Code etwas realistischer gestalten:
public class Document
{
public Document(String title)
{
if (String.IsNullOrWhiteSpace(title))
throw new ArgumentException("title");
Title = title;
}
public String ApprovedBy { get; private set; }
public DateTime? ApprovedOn { get; private set; }
public Boolean IsApproved { get; private set; }
public Boolean IsPublished { get; private set; }
public String PublishedBy { get; private set; }
public DateTime? PublishedOn { get; private set; }
public String Title { get; private set; }
public void Approve(String by)
{
if (IsApproved)
throw new InvalidOperationException("Already approved.");
ApprovedBy = by;
ApprovedOn = DateTime.Today;
IsApproved = true;
Raise(new ApprovedEvent(Title));
}
public void Publish(String by)
{
if (IsPublished)
throw new InvalidOperationException("Already published.");
if (!IsApproved)
throw new InvalidOperationException("Cannot publish until approved.");
PublishedBy = by;
PublishedOn = DateTime.Today;
IsPublished = true;
Raise(new PublishedEvent(Title));
}
}
Ich möchte Komponententests schreiben, die Folgendes bestätigen:
- Ich kann nur veröffentlichen, wenn das Dokument genehmigt wurde
- Ich kann ein Dokument nicht erneut veröffentlichen
- Bei der Veröffentlichung werden die Werte PublishedBy und PublishedOn ordnungsgemäß festgelegt
- Bei Veröffentlichung wird das PublishedEvent ausgelöst
Ohne Zugriff auf die Setter kann ich das Objekt nicht in den Status versetzen, der für die Durchführung der Tests erforderlich ist. Das Öffnen des Zugangs zu den Setzern verhindert den Zugang.
Wie haben Sie dieses Problem gelöst?