3 votes

Comment représenter les références dans les entités DDD

J'essaie de me familiariser avec le DDD et j'ai l'impression d'avoir une bonne compréhension des entités, des agrégats, des racines d'agrégats, des référentiels et des objets de valeur, ainsi que de la manière de représenter ces concepts dans le code.

Ce qui me pose encore problème, c'est la manière de représenter les références (c'est-à-dire les relations qui ne constituent pas un agrégat) dans le code réel. Disons que j'ai les deux agrégats suivants

DISCUSSIONGROUP (entity, aggregate root)
 +name: string
 +ENTRY (entity)
   +title: string
   +message: string
   +timestamp: date
   +madeByUser: USER

USER (entity, aggregate root)
 +name: string
 +email: string
 +memberOf: DISCUSSIONGROUP

Un utilisateur peut être membre d'un groupe de discussion mais l'entité utilisateur n'appartient pas au même agrégat. Il existe néanmoins une relation entre les deux (une référence). En regardant le code réel, j'implémenterais les relations d'agrégat comme suit (en utilisant C#) :

interface IDiscussionGroup {
    string Name { get; }
    IList<IEntry> { get; }
    ...
}

C'est-à-dire en utilisant de simples références C#. Implémenteriez-vous les références DDD (telles que décrites ci-dessus) de la même manière, c'est-à-dire en utilisant des références C# simples ?

interface IUser {
    IDiscussionGroup MemberOf { get; }
    ...
}

ou faut-il utiliser une autre construction pour indiquer le type de relation le plus faible ?

1voto

Thomas Jaskula Points 5914

Cela dépend vraiment de vos besoins. Il n'existe pas de méthode unique, mais je ferais en sorte que la propriété madeByUser de l'entité DISCUSSIONGROUP soit un ValueObject.

Pourquoi ? Parce que lorsque j'affiche les entrées de DisscusionGroup, je suis plutôt intéressé par le nom et peut-être l'email de l'utilisateur à afficher sur l'entrée. Je ne veux pas que cet utilisateur disparaisse de mon entrée lorsqu'elle est supprimée de la base de données. Si l'entité User avait davantage de propriétés et de comportements, cela ne m'intéresse pas lorsque j'affiche des informations sur l'utilisateur, par exemple, de sorte que le ValueObject conviendra parfaitement. De plus, vous pouvez partager ce VO entre plusieurs entrées sans avoir à restaurer l'instance de l'utilisateur concret pour chaque entrée.

D'autre part, l'agrégat User est-il utilisé dans le même contexte que le groupe de discussion ? Ce que je veux dire, c'est que le DiscussionGroup pourrait être une Entité dans un contexte (par exemple dans le cas d'utilisation du Front-office) et un objet de valeur dans le backoffice de gestion des utilisateurs (nous ne sommes pas intéressés par la gestion des groupes de discussion mais seulement par celle des utilisateurs, donc une simple information sur le disscussiongroup est suffisante). Cependant, il se peut que vous souhaitiez avoir une référence de l'entité DisscussionGroup à l'entité User ou qu'un DiscussionGroup devienne également un VO dans ce cas. Avez-vous besoin de récupérer tous les groupes de discussion et toutes les entrées pour un utilisateur donné ? Ou bien n'avez-vous besoin que de quelques informations que vous pourriez intégrer dans un objet de valeur ?

Je suis désolé si je n'ai pas très bien répondu à votre question, mais faire des références directes ou simplement utiliser une sorte d'Id partagée entre les agrégats ou utiliser VO dépend vraiment des cas d'utilisation et de l'environnement de travail. comportement que vous devez mettre en œuvre.

Personnellement, je vérifie si j'ai défini de bonnes limites d'agrégat, si je peux récupérer toutes les données dans l'agrégat sans faire de Lazy Loading et d'autres choses comme ça.

D'autres ont peut-être un autre point de vue.

0voto

Arnis L. Points 18316

Les termes "tient quelque chose" et "appartient à quelque chose" se ressemblent.

La différence est - quand ce qui est construit.

public class User{
  public IList<DiscussionGroup> GroupMembership{get; private set;}
  public User(){
    GroupMembership=new List<DiscussionGroup>();
  }
  public void JoinGroup(DiscussionGroup group){
    GroupMembership.Add(group);
  }
  public bool IsMemberOf(DiscussionGroup group){
    return GroupMembership.Contains(group);
  }
  public void EnsureMembership(DiscussionGroup group){
    ThrowIf(!IsMemberOf(this),
      "User is not a member of this discussion group");
  }
}
public class DiscussionGroup{
  public IList<Discussion> Discussions {get;private set;}
  public DiscussionGroup(){
    Discussions=new List<Discussion>();
  }
  public Discussion CreateDiscussion(string name, Post firstPost){
    CurrentUser.EnsureMembership(this);
    var discussion=new Discussion(this, name, firstPost);
    Discussions.Add(discussion);
    return discussion;
  }
}
public class Discussion{
  public DiscussionGroup Group{get; private set;}
  public Discussion(DiscussionGroup group, string name, Post firstPost){
    CurrentUser.EnsureMembership(group);
    Guard.Null(group);
    Group=group;
    Name=name;
    Posts=new List<Post>{firstPost};
  }
  public void WritePost(string text){
    CurrentUser.EnsureMembership(group);
    Posts.Add(new Post(this,text));
  }
}
public class Post{
  public Discussion Discussion{get; private set;}
  public string Text {get; private set;}
  public Post(Discussion discussion, string text){
    Guard.Null(discussion);
    Discussion=discussion;
    Text=text;
  }
}

//usage
var me=new User();
var you=new User();
var stackOverflow=new DiscussionGroup();
me.JoinGroup(stackOverflow);
you.JoinGroup(stackOverflow);

LoginAs(you);
var question="I'm trying to get a handle on DDD and feel that...";
var discussion=stackOverflow.CreateDiscussion
  ("How to represent references in DDD entites",question);

LoginAs(me);
var answer="'Holds something' and 'belongs to something'...";
discussion.WritePost(answer);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X