Working with polymorphic Child Entities

"[email protected] [domaindrivendesign]" <[email protected]> 25 May 2015 22:49:07 -0700
Newsgroups gmane.comp.programming.domain-driven-design
Message-ID <[email protected]>
I have been thinking of the best approach on how to deal with Aggregate entities that have polymorphic child entities and wonder if anyone has comments on whether this implementation is correct or whether I may be overlooking some potential pitfalls and what may be a better approach.
 

 The following code demonstrates a system for sending some sort of communication on varying schedules. Users can create 'Deliveries' that contain messages to be sent on one of two types of schedule either 'Hourly' or 'Daily'. A separate Windos Service will constants poll the Data Store to identify Deliveries that need to be sent. 
 

 

 THE DOMAIN
 

 class Delivery {
    Dictionary<Type, Func<ScheduleDto, ScheduleEntity>> ScheduleFactories = 
       new Dictionary<Type, Func<ScheduleDto, ScheduleEntity>> {
            { typeof(DailyScheduleDto), GetDailySchedule},
            { typeof(HourlyScheduleDto), GetHourlySchedule}
       };
    public Guid Id { get; private set; }
    public string Message get; private set; }
    public StatusEnum Status { get private set; }
    public Schedule { get; private set; }
    public Delivery(DeliveryDto dto){
        Id = dto.Id;
        Message = dto.Message;
        Status = StatusEnum.New;
        Schedule = ScheduleFactories[dto. Schedule.GetType()](dto. Schedule);
    }
    public void Update(DeliveryDto dto){
        Message = dto.Message;
        Schedule.Update(dto.Schedule);
    }
    public DateTime GetNextDeliverySchedule( DateTime after){
        return Schedule. GetNextDeliverySchedule(after) ;
    }
    public enum StatusEnum { New, InProgress, Complete }
    Schedule GetDailyScheduleEntity( ScheduleDto dto){
        return new DailyScheduleEntity(( DailyScheduleDto)dto);
    }
    Schedule GetHourlyScheduleEntity( ScheduleDto dto){
        return new HourlyScheduleEntity(( HourlyScheduleDto)dto);
    }
}
abstract class Schedule {
    public DateTime StartsOn { get; private set; }
    public abstract DateTime GetNextDeliverySchedule( DateTime after);
    public virtual void Update(ScheduleDto dto){
         StartsOn = dto.StartsOn;
    }
    public Schedule(ScheduleDto dto) {
        StartsOn = dto.StartsOn;
    }
}
class DailySchedule : Schedule {
    public DaysEnum Days { get; private set; }
    public override DateTime GetNextDeliverySchedule( DateTime after){
       return // logic for calculating the next day based on Days;
    }
    public DailySchedule(DailyScheduleDto dto)
        : base(dto)
    { 
        Days = dto.Days.ToEnum<DaysEnum>();
        base.Update(dto);
    }
    public override void Update(ScheduleDto dto){
        Days = ((DailyScheduleDto)dto).Days. ToEnum<DaysEnum>();
    }
    [Flags]
    public enum DaysEnum{
        Monday, Tuesday, Wednesday, Thursday, Friday
    }
}
class HourlySchedule : Schedule {
    public int Interval { get; private set }
    public override DateTime GetNextDeliverySchedule( DateTime after){
       return // logic for calculating the next hour based on interval;  
    }
    public HourlySchedule( HourlyScheduleDto dto)
        : base(dto)
    {
         Interval = dto.Interval;
    }
    public override void Update(ScheduleDto dto){
        Days = ((HoulryScheduleDto)dto). Interval;
        base.Update(dto);
    }
}
class DeliveryService : IDeliveryService {
     public void Add(DeliveryDto dto){
         var delivery = new Delivery(dto);
         unitOfWork.Add<Delivery>( delivery);
         unitOfWork.SaveChanges();
     }
     public void Update(DeliveryDto dto){
          var delivery = unitOfWork.Get<Delivery>(dto. Id);
          delivery.Update(dto);
          unitOfWork.SaveChanges();
     }
}  
 CONTRACTS
 
DeliveryDto{
    Guid Id {get; set;}
    string Description {get; set;}
    ScheduleDto Schedule {get; set;}
}
ScheduleDto{
   DateTime StartsOn {get; set;}
}
HourlyScheduleDto : ScheduleDto{
   int Interval {get; set;}
}
DailyScheduleDto : ScheduleDto{
   String Days {get; set;}
}  
 I would typically have specific dtos for creating new instances and performing updates, but reuse the same types here for simplicity.
 

 
 Although there is an argument that passing Dtos directly to Entities would tightly couple clients to the domain, my intention is to provide a thin facade-type layer that would be responsible for 'upgrading' dtos to maintain compatibility with existing clients should the current dto's need to change to accommodate changing business needs