2011-04-22 87 views
0

下面的代码详细描述了我的设计问题。我有一个数据库中的任务表,可以有不同类型的重复模式。任务表具有每个可能的重复模式字段的列。但是,我希望Task对象根据db中的哪个模式创建适当的模式。下面的代码将做到这一点,但接下来的问题是调用代码将不得不在检查任何操作之前检查返回的类型。将平面DB模型映射到OO模型

例如

var t = new Task(); 
var pattern = t.Recurrance; 

调用代码不知道正在创建哪种类型的递归?

什么是更好的方式来建模?

class Task 
{ 
    private int recurrenceType = 0; //pulled from the db 
    public Task() 
    { 
     //determine recurrence type from database 
     switch (recurrenceType) 
     { 
      case 0: 
       Recurrance = new RecurrenceDaily(); 
       break; 
      case 1: 
       Recurrance = new RecurrenceMonthly(); 
       break; 
      case 2: 
       Recurrance = new RecurrenceWeekly(); 
       break; 
     } 
    } 
    public RecurrenceBase Recurrance { get; set;} 
} 

abstract class RecurrenceBase 
{ 
    public int Frequency { get; set; } 
} 

class RecurrenceDaily : RecurrenceBase 
{ 
    public bool Weekends { get; set; } 
} 

class RecurrenceWeekly : RecurrenceBase 
{ 
    public DaysOfWeekFlagsEnum DaysOfWeek { get; set; } 
} 

class RecurrenceMonthly : RecurrenceBase 
{ 
    public byte DayOfMonth { get; set; } 
    public WeekEnum Week { get; set; } 
    public DayOfWeekEnum DayOfWeek { get; set; } 
} 

回答

0

那么,你在这段代码中有许多问题。对于初学者来说,您的Recurrance将始终为RecurranceDaily,因为您在构造函数中创建了Recurrance,无法在创建Recurrance之前设置RecurranceType。必须先创建对象才能设置对象中的任何数据。除非您在构造函数中设置了这些数据,否则您将始终具有默认状态(对于整数为0,并将其初始化为0)。

其次,您没有resternType的setter,并且由于该值是私有的,因此在构建之后无法对其进行设置。

第三,您的Recurrance成员是一个只有一个getter的属性,但在构造函数中您将它设置为value。这也不会编译,因为你没有设置。

+0

谢谢..通过添加Set to Recurrence属性来修复它。 – 2011-04-22 21:44:48

+0

如果你不想让别的东西叫它,你可以把它变成一个私人二传手。但是,你还没有提到我的前两点。 – 2011-04-22 21:48:08

0

我不确定你是否给了我们足够的信息来对设计方向做出明智的建议,但是你可能想要考虑基于复发类型的不同类型的任务,例如DailyTask,WeeklyTask,MonthlyTask 。

然后,您可以在Task子类中放置适当的逻辑。例如。

var task = db.GetTaskById(15); 
task.Schedule(startDate); 

你的数据库的代码将通过ID获取任务,弄清楚它是一个WeeklyTask,例如,建立适当内复发了。然后它会有一个Schedule方法,对于从startDate开始的每周任务是有意义的。

public interface ITask 
{ 
    public void Schedule(DateTime startDate); 
} 

public abstract class TaskBase : ITask 
{ 
    // common methods... 
    public abstract void Schedule(DateTime startDate); 
} 

public class WeeklyTask : TaskBase 
{ 
    public override void Schedule(DateTime startDate) 
    { 
     var startWeek = GetStartOfWeek(startDate); 
     var firstDate = startWeek.AddDays(DaysOfWeek[0]); 
     ... 
    } 
} 
+0

也可以工作..返回不同类型的任务(而不是一个不同的重复模式)。然而,问题仍然存在......它只是移到了'var task = db.GetTaskById(15);'调用中,因为这个调用必须返回基类。调用者知道返回哪种类型的任务的唯一方法是对返回的对象执行类型检查。 – 2011-04-22 21:50:36

+0

@pmaroun - 但另一部分是将你正在做的事情转移到特定的任务子类中。也就是说,每个任务都包含对其进行操作的代码。它通过界面公开其操作。在这个例子中,我已经使用了单一的Schedule调用方法,但是任何其他的操作都将以相似的方式处理。通过这种方式,调用代码只需要知道接口契约,而不是每种任务类型都有不同的代码。这是一个基本的面向对象原则,即封装:每个类都应该包含数据**和**以对这些数据进行操作的代码。 – tvanfosson 2011-04-22 21:56:57

0

显然还有更多您的情况比这里满足的眼睛,但我想看看这个答案从SO About Inversion of Control And Dependency Injection。然后继续The Martin Fowler Article。使用IoC和DI,您可以将您的RecurrenceBase抽象为更像IRecur接口的“DoSomething”事件等,以创建共同点。也许是一个封装调度的“RecurrenceEventArgs”类。

我希望这能让你指出正确的方向。

0

您正在创建一个继承层次结构 - 一个面向对象的构造 - 但是您显示的类决定不是面向对象的,因为它们不包含行为并且仅暴露数据。

这是继承的不当使用,至少是造成你痛苦的部分原因。

当您继承时,您声明子类可以与父类使用相同的合同。随着你展示的课程和你使用它们的方式,这是不正确的。