2016-08-01 34 views
1

Ich bin in der Verwendung von DDD für eine Beispielanwendung, für jetzt bin ich auf Domain-Ereignisse fest. Da es ziemlich gute EventDispatcher gibt, möchte ich das Rad nicht neu erfinden. Aber diese Implementierungen erfordern alle, dass meine Events ihr EventInterface implementieren. Ich möchte die Implementierung meiner Domain Events von jeglicher Art der Implementierung trennen. Wie soll ich dieses Problem angehen?Wie Abhängigkeit im Domänenkontext bei der Verwendung von Vendor Event Dispatcher nicht verwendet werden

+0

Haben Sie sich Guava Eventbus angesehen? Kein EventInterface da denke ich https://github.com/google/guava/wiki/EventBusExplained –

+0

Vielleicht denk auch daran, dein Domain-Event von der Anwendungsebene zu senden, in diesem Fall ist es IMO ein Problem, von einem fwk abhängig zu sein. Ich sage das, weil Sie manchmal innerhalb eines beschränkten Kontextes Domänenereignisse brauchen. Eventuell werden Ihre Events nur außerhalb Ihres Kontextes verwendet. –

+0

@RonanQuillevere Ich benutze PHP, aber danke für den Vorschlag –

Antwort

1

Zwei Möglichkeiten, die ich denken kann

1) Führen Sie die Idee eines Adapters vor dem Eventdispatcher; Der Adapter akzeptiert Ereignisse im von der Domäne erstellten Format und "serialisiert" dieselben Daten in das Formular, das von der verwendeten Dispatcher-Implementierung benötigt wird.

2) Erstellen Sie die Domain-Ereignisse mit einem Builder API; Die Domäne definiert den Builder-Vertrag, aber die Implementierung unter den Abdeckungen ist spezifisch für den von Ihnen verwendeten Ereignis-Dispatcher.

+0

Danke, ich habe den Adapter erstellt, damit ich bei Bedarf die gesamte Infrastruktur-Ebene ändern kann. –

1

Hier ist meine impl:

/// <summary> 
/// Contains the contract for publishing domain events. 
/// </summary> 
public interface IDomainEventPublisher 
{ 
    /// <summary> 
    /// Publishes the domain events. 
    /// </summary> 
    /// <param name="domainEvents">events to be published</param> 
    Task Publish(IEnumerable domainEvents); 

    /// <summary> 
    /// Subscribes the list of subscribers. 
    /// </summary> 
    /// <param name="subscribers">event subscriptions</param> 
    void Subscribe(params IDomainEventSubscription[] subscribers); 

    /// <summary> 
    /// Subscribes to the event. 
    /// </summary> 
    /// <typeparam name="T">event to subscribe too</typeparam> 
    /// <returns>event subscription</returns> 
    DomainEventSubscription<T> SubscribeTo<T>(); 
} 

/// <summary> 
/// Publishes events to registered subscribers. 
/// </summary> 
public class DefaultDomainEventPublisher : IDomainEventPublisher 
{ 
    readonly List<IDomainEventSubscription> subscriptions; 

    /// <summary> 
    /// Creates a new instance of the object. 
    /// </summary> 
    public DefaultDomainEventPublisher() 
    { 
     subscriptions = new List<IDomainEventSubscription>(); 
    } 

    /// <summary> 
    /// Subscribes to the event. 
    /// </summary> 
    /// <typeparam name="T">event to subscribe too</typeparam> 
    /// <returns>event subscription</returns> 
    public DomainEventSubscription<T> SubscribeTo<T>() 
    { 
     var subscription = new DomainEventSubscription<T>(); 

     subscriptions.Add(subscription); 

     return subscription; 
    } 

    /// <summary> 
    /// Subscribes the list of subscribers. 
    /// </summary> 
    /// <param name="subscribers">event subscriptions</param> 
    public void Subscribe(params IDomainEventSubscription[] subscribers) 
    { 
     subscriptions.AddRange(subscribers); 
    } 

    /// <summary> 
    /// Publishes the domain events. 
    /// </summary> 
    /// <param name="domainEvents">events to be published</param> 
    public virtual async Task Publish(IEnumerable domainEvents) 
    { 
     foreach (var @event in domainEvents) 
     { 
      var subscribers = subscriptions.Where(s => s.CanHandleType(@event.GetType())); 

      foreach (var subscriber in subscribers) 
      { 
       await subscriber.Handle(@event); 
      } 
     } 
    } 
} 

/// <summary> 
/// Handles the subscription services for an event. 
/// </summary> 
/// <typeparam name="T"></typeparam> 
public class DomainEventSubscription<T> : IDomainEventSubscription 
{ 
    readonly List<object> subscriptionMethods; 

    /// <summary> 
    /// Constructs a new instance. 
    /// </summary> 
    public DomainEventSubscription() 
    { 
     this.subscriptionMethods = new List<object>(); 
    } 

    /// <summary> 
    /// Adds the subscription method to the subscription. 
    /// </summary> 
    /// <param name="subscriptionMethod">subscription method</param> 
    public void AddSubscriptionMethod(ISubscriptionMethod subscriptionMethod) 
    { 
     subscriptionMethods.Add(subscriptionMethod); 
    } 

    /// <summary> 
    /// Returns whether or not the subscription can handle the specified type. 
    /// </summary> 
    /// <param name="type"></param> 
    /// <returns>whether it can handle the type</returns> 
    public bool CanHandleType(Type type) 
    { 
     return type.IsAssignableFrom(typeof(T)); 
    } 

    /// <summary> 
    /// Publishes the event. 
    /// </summary> 
    /// <param name="event">event to publish</param> 
    public async Task Handle(object @event) 
    { 
     foreach (var subscriptionMethod in subscriptionMethods) 
     { 
      await (subscriptionMethod as dynamic).Handle(@event); 
     } 
    } 
} 

/// <summary> 
/// Contains the contract for event subscribers. 
/// </summary> 
public interface IDomainEventSubscription 
{ 
    /// <summary> 
    /// Publishes the event. 
    /// </summary> 
    /// <param name="event">event to publish</param> 
    Task Handle(object @event); 

    /// <summary> 
    /// Returns whether or not the subscription can handle the specified type. 
    /// </summary> 
    /// <param name="type"></param> 
    /// <returns>whether it can handle the type</returns> 
    bool CanHandleType(Type type); 
} 

/// <summary> 
/// Contacts the contract for subscription methods. 
/// </summary> 
public interface ISubscriptionMethod 
{ 
    /// <summary> 
    /// Publishes the event. 
    /// </summary> 
    /// <param name="event">event to publish</param> 
    Task Handle(object @event); 
} 

/// <summary> 
/// Base class for subscription method implementations. 
/// </summary> 
/// <typeparam name="T"></typeparam> 
public abstract class SubscriptionMethod : ISubscriptionMethod 
{ 
    /// <summary> 
    /// Publishes the event. 
    /// </summary> 
    /// <param name="event">event to publish</param> 
    public abstract Task Handle(object @event); 
} 

/// <summary> 
/// Publishes events using delegates. 
/// </summary> 
/// <typeparam name="T"></typeparam> 
public class DelegateSubscriptionMethod<T> : ISubscriptionMethod 
{ 
    readonly Func<T, Task> delegateAction; 

    /// <summary> 
    /// Constructs a new instance. 
    /// </summary> 
    /// <param name="action">delegate used for publishing</param> 
    public DelegateSubscriptionMethod(Func<T, Task> action) 
    { 
     delegateAction = action; 
    } 

    /// <summary> 
    /// Publishes the event using a delegate. 
    /// </summary> 
    /// <param name="event">event to publish</param> 
    public async Task Handle(object @event) 
    { 
     await delegateAction(@event as dynamic); 
    } 
} 

/// <summary> 
/// Provides an extension method for publishing an event using a delegate. 
/// </summary> 
public static class DomainEventSubscriptionExtensions 
{ 
    /// <summary> 
    /// Adds an event subscription for publishing using the specified delegate. 
    /// </summary> 
    /// <typeparam name="T">event the subscription is subscribed too</typeparam> 
    /// <param name="subscription">event subscription</param> 
    /// <param name="action">delegate used for publishing</param> 
    /// <returns>event subscription</returns> 
    public static DomainEventSubscription<T> UsingDelegate<T>(this DomainEventSubscription<T> subscription, Func<T, Task> action) 
    { 
     var subscriptionMethod = new DelegateSubscriptionMethod<T>(action); 

     subscription.AddSubscriptionMethod(subscriptionMethod); 

     return subscription; 
    } 
} 

Hier einige grundlegende Verwendung ist:

publisher.SubscribeTo<DocumentOwnerChanged>() 
    .UsingDelegate(
     async a => await messageGateway.DocumentOwnerChanged(1, 1, 1)); 

Ich habe auch eine Implementierung für die automatische abonnieren DI-Container verwenden. Lassen Sie mich wissen, wenn Sie das auch sehen möchten.

+0

Dies ist eine Lösung, aber leider benutze ich PHP und war dabei, ein Hersteller-Paket zu verwenden. –