views:

67

answers:

5

We have a class Event (it's actually named differently, but I'm just making abstraction):

public class Event
{
    public string Name { get; set; }
    public string Description { get; set; }
    public EventType EventType { get; set; }
}

We need to build an instance of a Message class with this object, but depending on the EventType, we use a different builder:

switch (event.EventType)
{
    case EventType.First:
        message = FirstMessageBuilder.Build(event);
        break;
    case EventType.Second:
        message = SecondMessageBuilder.Build(event);
        break;
}

Do you think this is acceptable, or should we take the following approach:

Make an abstract class:

public class Event
{
    public string Name { get; set; }
    public string Description { get; set; }
    public abstract Message BuildMessage();
}

Then derive two classes: class FirstMessage and class SecondMessage and make the domain objects responsible for building the message.

I hope it isn't too abstract. The bottom line is we need to transform one class to another. A simple mapper won't do, because there are properties with XML content and such (due to a legacy application making the events). Just accept what we're trying to do here.

The real question is: can a domain object be responsible for such a transformation, or would you not recommend it? I would avoid the ugly switch statement, but add complexity somewhere else.

+1  A: 

Strictly speaking, a domain object shouldn't be responsible for anything other than representing the domain. "Changing type" is clearly a technical issue and should be done by some kind of service class, to maintain a clear separation of concerns...

Thomas Weller
+2  A: 

Whilst I agree with Thomas, you might want to look at the following design patterns to see if they help you:

  • Vistor Pattern
  • Double-Dispatch Pattern
  • Builder Pattern
Codebrain
A: 

There are few possible solutions. To use abstract factory:

public interface IMessageFactory 
{
    Message Create();
}

public class FirstMessageFactory : IMessageFactory
{
    public Message Create()
    {
        //...
    }
}

public class SomeService
{
     private readonly IMessageFactory _factory;

     public SomeService(IMessageFactory factory)
     {
          _factory = factory;
     }

     public void DoSomething() 
     {
         var message = _factory.Create();
         //...
     }
}

Now you can wire IoC container to right factory for requested service.

To use Assembler which makes the transformation:

public interface IAssembler<TSource, TDestination> 
{
    TDestination Transform(TSource source);
}

This is quite similar to factory pattern, but if you are dependent on EventType, its possible to do it like:

public interface IAssembler<TEventType> 
{
    object Transform(object source);
}
Marek Tihkan
+1  A: 

In order to gain the readability of

var message = eventInstance.AsMessage();

as well following the single responsibility principle, you could define AsMessage() as an extension method of the event type.

Martin R-L
A: 

I would encapsulate the logic into a separate Factory/Builder class, and use an extension method on Event to call the builder.

This would give you the best of both worlds.

Vijay Patel