Rompere il "linguaggio ubiquitario" avendo un contenitore IoC nel modello di dominio?

5

Sono un po 'nuovo in DDD e sopporto me se la mia comprensione sembra lontana.

La mia domanda riguarda la soluzione di Udi agli eventi del dominio, in particolare la classe DomainEvents (vedi codice sotto)

Un estratto dal codice di Udi. Vive il modello di dominio come una classe statica.

public static class DomainEvents
{ 
   [ThreadStatic] //so that each thread has its own callbacks
   private static List<Delegate> actions;

   public static IContainer Container { get; set; } //as before

   //Registers a callback for the given domain event
   public static void Register<T>(Action<T> callback) where T : IDomainEvent
   {
      if (actions == null)
         actions = new List<Delegate>();

      actions.Add(callback);
  }

  //Clears callbacks passed to Register on the current thread
  public static void ClearCallbacks ()
  { 
      actions = null;
  }

  //Raises the given domain event
  public static void Raise<T>(T args) where T : IDomainEvent
  {
     if (Container != null)
        foreach(var handler in Container.ResolveAll<Handles<T>>())
           handler.Handle(args);

     if (actions != null)
         foreach (var action in actions)
             if (action is Action<T>)
                 ((Action<T>)action)(args);
  }
} 

In base al codice precedente, affinché DomainEvents venga utilizzato dal modello di dominio, è necessario che entrambi si trovino nello stesso assembly. Che rende corretta la parte DomainEvents del modello di dominio? (Potrei sbagliarmi qui)

Quindi la mia domanda è: DomainEvents interrompe la regola "lingua ubiquitaria di DDD" ? Perché la sua implementazione non riguarda alcun dominio.

La mia altra preoccupazione è che il membro statico IContainer crea una dipendenza da ioc-container nel modello di dominio. Anche se non sono sicuro che il% co_de di Udi sia un'interfaccia o un vero contenitore IoC.

La mia seconda domanda è: Cos'è questo IContainer nella classe IContainer ? Se è veramente un contenitore IoC, allora non infrange la regola di "DDD dovrebbe non hai un'infrastruttura nel dominio "? La mia comprensione è corretta sul fatto che un contenitore IoC sia considerato un'infrastruttura? (Per favore correggimi se sbaglio)

Se potresti trovare qualcosa di confuso, per favore dillo.

Modifica

Ho costruito i miei progetti in cui il modello di dominio è separato sul proprio assembly (io chiamo questo livello aziendale) senza alcun riferimento a nessun componente dell'infrastruttura. Vedi architettura cipolla .

Ora voglio incorporare il pattern degli eventi del dominio. Ma così facendo mi costringe ad aggiungere componenti di infrastruttura al mio livello aziendale. I componenti sono DomainEvents e un framework IoC solo per soddisfare DomainEvents , entrambi non hanno alcuna relazione con il dominio.

L'idea di DDD non riguarda la separazione dell'infrastruttura dal dominio?

Ora interpreterò il programmatore pragmatico, volevo solo sapere che è generalmente giusto farlo? ci sono alternative? Cosa ne pensi di questo approccio? Mi sto perdendo qualcosa di essenziale qui?

    
posta Yorro 29.12.2013 - 03:34
fonte

3 risposte

3

Sono d'accordo con te per la prima sotto-domanda:

Dal mio punto di vista la classe DomainEvents è un codice infrastururo che non dovrebbe essere implementato nel dominio stesso.

Quindi invece di una classe statica DomainEvents nel livello del dominio preferirei una classe nonstatica DomainEvents in un livello infrastruttura che implementa un'interfaccia IEventHandling (nel livello dominio) con metodi Register , Raise , ...

Il contenitore di ioc annulla l'implementazione di IEventHandling come singleton per ogni classe che ha bisogno di DomainEvents .

 > My 2nd question is: What is this IContainer in the DomainEvents class?

Il contenitore IOC è un codice infrastruttura in modo che sia nascosto dietro un'interfaccia.

Dal punto di vista dell'architettura preferisco fare riferimento al contenitore ioc solo in un modulo di inizializzazione e da nessun'altra parte. Pertanto l'icontainer non dovrebbe essere referenziato dalla classe DomainEvents. Preferirei invece avere un metodo DomainEvents.RegisterHandler e rinominerei DomainEvents.Register in DomainEvents.RegisterEvent .

Il modulo di inizializzazione del contenitore ioc è repsonsible per registrare tutti i gestori.

    
risposta data 29.12.2013 - 12:29
fonte
1

Il DomainEvents non è parte del modello di dominio, è un componente dell'infrastruttura utilizzato per supportare modelli di dominio liberamente accoppiati.

Il contenitore non è strettamente richiesto (motivo per cui il codice come scritto consente di essere nullo), consente solo uno stile dichiarativo piuttosto che imperativo di handle di registrazione.

In altre parole, puoi usarlo in questo modo:

public SomeClass()
{
    DomainEvents.Register<SomethingHappened>(() => RespondToSomething());

    void RespondToSomething() { ... }
}

O come questo:

public class SomeHandler : Handles<SomethingHappened>
{
    public void Handle(SomethingHappened e) { ... }
}

Entrambi realizzano più o meno la stessa cosa, ma la prima versione richiede che un'istanza esista prima l'evento sia pubblicato. Ogni versione ha il suo posto; la prima versione tende ad essere più utile nelle applicazioni rich client, dove è essenzialmente il noto pattern Event Broker, e la seconda versione è più utile nelle applicazioni di servizio, dove nel mondo di Udi il pattern è ora effettivamente formalizzato come In-Memory Bus e non è molto più di un generico messaggio in-process, non duraturo.

E sì, IContainer è in effetti il contenitore IoC, ma ancora una volta, questo è un componente di infrastruttura, nulla nel modello di dominio stesso dipende dal contenitore.

Non sono sicuro di cosa intendi quando ti riferisci a "rompere [ing] la regola di non avere infrastrutture nel dominio" - Non ho familiarità con questa regola, ma anche se vuoi seguirla, a volte la purezza ha davvero bisogno di prendere un sedile posteriore al pragmatismo. Se il risultato finale sta comprimendo 10 dipendenze verso il basso in 1 dipendenza senza un wrapper, questa è una vittoria, indipendentemente dall'architettura che stai cercando di seguire.

    
risposta data 29.12.2013 - 03:56
fonte
0

L'idea di un qualche tipo di Pubblica-Iscriviti all'interno del dominio non è male. Potrebbe essere una buona astrazione che all'interno del dominio, alcuni eventi accadono e altri possono reagire a loro. E esiste una sorta di mediazione, che consente un accoppiamento lento tra editori e abbonati. Quindi, all'interno del linguaggio ubiquitario, ci può essere "l'entità X si abbona agli eventi di tipo Y e farà Z" e "l'entità X pubblica l'evento di tipo Y quando Z accade". Questo risponde alla tua prima domanda.

Ma l'implementazione è sbagliata. Ci dovrebbe essere un qualche tipo di servizio, che media tra gli editori e gli abbonati. E all'interno del dominio, il servizio sarà rappresentato da un'interfaccia. L'effettiva implementazione dell'interfaccia sarà all'interno dell'infrastruttura. In questo modo, non è necessario alcun contenitore nel dominio, perché il contenitore è parte dell'implementazione. E questo risponde alla tua seconda domanda.

Ad esempio, nel tuo codice, stai creando dipendenza dal tuo dominio sul contenitore IoC. Ma IoC fa parte dell'infrastruttura, quindi la dipendenza è il modo sbagliato. Aggiungendo un'interfaccia in mezzo, puoi correggere la direzione della dipendenza e inserire l'implementazione in infrastruttura, a cui appartiene.

    
risposta data 29.12.2013 - 11:49
fonte

Leggi altre domande sui tag