【发布时间】:2015-08-04 16:33:45
【问题描述】:
我一直在考虑处理具有多态子的聚合实体的最佳方法,想知道是否有人可以告诉我下面的实现是否是正确的实现,或者我是否可能忽略了一些潜在的陷阱。
以下代码演示了一个系统,用于按不同的时间表发送某种通信。
领域
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 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 GetNextExecution(DateTime after){
return Schedule.GetNextExecution(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 GetNextExecution(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 GetNextExecution(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){
if(!(dto is DialyScheduleDto)) throw new InvalidOperationException();
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 GetNextExecution(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){
if(!(dto is HourlyScheduleDto)) throw new InvalidOperationException();
Interval = ((HoulryScheduleDto)dto).Interval;
base.Update(dto);
}
}
class DeliveryService : IDeliveryService {
public void Add(DeliveryDto dto){
var delivery = new Delivery(dto);
var scheduledTask = new ScheduledTask(
delivery.Id,
delivery.GetNextExecution(after: DateTime.Now)
);
unitOfWork.Add<ScheduledTask>(scheduledTask);
unitOfWork.Add<Delivery>(delivery);
unitOfWork.SaveChanges();
}
public void Update(DeliveryDto dto){
var delivery = unitOfWork.Get<Delivery>(dto.Id);
delivery.Update(dto);
unitOfWork.SaveChanges();
}
public void SendAll(){
var scheduledTasks = unitOfWork.GetAll<ScheduledTask>(st => st.ExecutionDateTime < DateTime.Now && st.Status == ScheduledTaskStatus.New);
scheduledTasks.ForEach(//Send to subsystem for execution);
}
}
合同
public class DeliveryDto{
public Guid Id {get; set;}
public string Message {get; set;}
public ScheduleDto Schedule {get; set;}
}
public class ScheduleDto{
public DateTime StartsOn {get; set;}
}
public class HourlyScheduleDto : ScheduleDto{
public int Interval {get; set;}
}
public class DailyScheduleDto : ScheduleDto{
public String Days {get; set;}
}
我通常会使用特定的 dto 来创建新实例和执行更新,但为了简单起见,在此处重复使用相同的类型。
虽然有一种观点认为将 Dtos 直接传递给 Entities 会使客户端与域紧密耦合,但我的意图是提供一个瘦的外观类型层,该层将负责“升级”dtos 以保持与现有客户端的兼容性。当前 dto 需要进行更改以适应不断变化的业务需求
【问题讨论】:
标签: c# domain-driven-design soa