2011-04-22 73 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

您正在創建一個繼承層次結構 - 一個面向對象的構造 - 但是您顯示的類決定不是面向對象的,因爲它們不包含行爲並且僅暴露數據。

這是繼承的不當使用,至少是造成你痛苦的部分原因。

當您繼承時,您聲明子類可以與父類使用相同的合同。隨着你展示的課程和你使用它們的方式,這是不正確的。