Kann eine Aggregationsinvariante eine Regel enthalten, die auf Informationen von anderen Quellen basiert?
Aggregate können immer die Informationen in ihren eigenen Zuständen und das Argument, dass ihre commands erhalten.
Jemand verwendet, um auf die Anwendungsdienste über Singletons, Service Locators und so weiter zugreifen, aber IMO, das ist ein Geruch von eng gekoppelten Anwendungen. Sie vergessen, dass die Argumente der Methoden effektive Injektoren der Abhängigkeit sind! :-)
In DDD kann eine Aggregationsinvariante eine Regel basierend auf Informationen in einem anderen Aggregat enthalten?
No.
sei denn, der zweite Aggregat über Befehle Argumente versehen ist, selbstverständlich.
WARNUNG! ! !
Ich habe ein Unternehmen namens Vermögen (Ausrüstung) ...
... (und a) zweites Aggregat genannt AssetType ...
Das letzte Mal, dass ich bewältigen musste eine ähnliche Struktur, es war ein Schmerz.
Wahrscheinlichkeiten sind, dass Sie die falschen Abstraktionen wählen.
habe ich meine Invariante falsch?
Wahrscheinlich ... Haben Sie nach dem Domänenexperten gefragt? Ist er spricht über "TagTypes"?
You should never abstract on your own.
Entitäten des Typs X
halten einen Verweis auf eine Instanz von X-Type
sind fast immer ein Geruch von Über-Abstraktion, die in der Hoffnung auf Wiederverwendung, macht das Modell starr und unflexibel für die Geschäftsentwicklung.
ANTWORT
Wenn (und nur dann) der Domain-Experte beschrieben tatsächlich das Modell in dieser Hinsicht ein möglicher Ansatz ist die folgende:
- Sie können eine
AssetType
Klasse erstellen mit Eine Factory-Methode, die einen IEnumerable<Tag>
in einen TagSet
and throws entweder MissingMandatoryTagException
oder UnexpectedTagException
verwandelt, wenn ein Teil des Tags fehlt oder unerwartet ist.
- in der
Asset
Klasse, ein Befehl RegisterTags
würde eine AssetType
und eine IEnumerable<Tag>
akzeptieren, werfen die MissingMandatoryTagException
und WrongAssetTypeException
(beachten Sie, wie Ausnahmen wichtig sind Invarianten zu gewährleisten).
bearbeiten
so etwas, aber viel mehr dokumentiert:
public class AssetType
{
private readonly Dictionary<TagType, bool> _tagTypes = new Dictionary<TagType, bool>();
public AssetType(AssetTypeName name)
{
// validation here...
Name = name;
}
/// <summary>
/// Enable a tag type to be assigned to asset of this type.
/// </summary>
/// <param name="type"></param>
public void EnableTagType(TagType type)
{
// validation here...
_tagTypes[type] = false;
}
/// <summary>
/// Requires that a tag type is defined for any asset of this type.
/// </summary>
/// <param name="type"></param>
public void RequireTagType(TagType type)
{
// validation here...
_tagTypes[type] = false;
}
public AssetTypeName Name { get; private set; }
/// <summary>
/// Builds the tag set.
/// </summary>
/// <param name="tags">The tags.</param>
/// <returns>A set of tags for the current asset type.</returns>
/// <exception cref="ArgumentNullException"><paramref name="tags"/> is <c>null</c> or empty.</exception>
/// <exception cref="MissingMandatoryTagException">At least one of tags required
/// by the current asset type is missing in <paramref name="tags"/>.</exception>
/// <exception cref="UnexpectedTagException">At least one of the <paramref name="tags"/>
/// is not allowed for the current asset type.</exception>
/// <seealso cref="RequireTagType"/>
public TagSet BuildTagSet(IEnumerable<Tag> tags)
{
if (null == tags || tags.Count() == 0)
throw new ArgumentNullException("tags");
TagSet tagSet = new TagSet();
foreach (Tag tag in tags)
{
if(!_tagTypes.ContainsKey(tag.Key))
{
string message = string.Format("Cannot use tag {0} in asset type {1}.", tag.Key, Name);
throw new UnexpectedTagException("tags", tag.Key, message);
}
tagSet.Add(tag);
}
foreach (TagType tagType in _tagTypes.Where(kvp => kvp.Value == true).Select(kvp => kvp.Key))
{
if(!tagSet.Any(t => t.Key.Equals(tagType)))
{
string message = string.Format("You must provide the tag {0} to asset of type {1}.", tagType, Name);
throw new MissingMandatoryTagException("tags", tagType, message);
}
}
return tagSet;
}
}
public class Asset
{
public Asset(AssetName name, AssetTypeName type)
{
// validation here...
Name = name;
Type = type;
}
public TagSet Tags { get; private set; }
public AssetName Name { get; private set; }
public AssetTypeName Type { get; private set; }
/// <summary>
/// Registers the tags.
/// </summary>
/// <param name="tagType">Type of the tag.</param>
/// <param name="tags">The tags.</param>
/// <exception cref="ArgumentNullException"><paramref name="tagType"/> is <c>null</c> or
/// <paramref name="tags"/> is either <c>null</c> or empty.</exception>
/// <exception cref="WrongAssetTypeException"><paramref name="tagType"/> does not match
/// the <see cref="Type"/> of the current asset.</exception>
/// <exception cref="MissingMandatoryTagException">At least one of tags required
/// by the current asset type is missing in <paramref name="tags"/>.</exception>
/// <exception cref="UnexpectedTagException">At least one of the <paramref name="tags"/>
/// is not allowed for the current asset type.</exception>
public void RegisterTags(AssetType tagType, IEnumerable<Tag> tags)
{
if (null == tagType) throw new ArgumentNullException("tagType");
if (!tagType.Name.Equals(Type))
{
string message = string.Format("The asset {0} has type {1}, thus it can not handle tags defined for assets of type {2}.", Name, Type, tagType.Name);
throw new WrongAssetTypeException("tagType", tagType, message);
}
Tags = tagType.BuildTagSet(tags);
}
}
Danke für die Antwort. Ich denke, die mögliche Konsistenz ist die Antwort, wie Sie gesagt haben. Obwohl @ GiacomoTesio auch – MJM
große Hilfe geleistet hat, würde ich auch anderen zeigen, dass der Instinkt, Bedingungen abzuleiten, allzu einfach ist. Wie wir festgestellt haben, sind die tatsächlichen Fakten, dass Assets aus AssteTypes erstellt werden, dann aber mehr oder weniger vom ursprünglichen Typ getrennt sind. Die Referenz kann zu jedem Zeitpunkt auf die ursprüngliche Spezifikation des Assets zurückgebracht werden und als Ergebnis in gewisser Weise aktualisiert werden, aber diese Aktion wird vom Aufrufer aufgerufen und nicht als Nebeneffekt des Speicherns des ursprünglichen Typs. Diese Erkenntnis hat enorm geholfen. – MJM