2012-11-22 122 views
1

參考發佈的問題here,請您評論一下,如果這是一個很好的方法來解決擴展類的可選行爲,那麼使用組合而不是繼承。 Plannable行爲在這裏由策略模式擴展。具有虛擬混淆策略的策略模式

因此,類Task可以可選地具有各種行爲的任意組合。 Plannable只是其中之一,因此繼承在這裏顯然沒有意義。

問題是當Task沒有特別的行爲時該怎麼做?我看到一些可能的方法:

  1. 實例化每項任務的具體策略,而當Task不是Plannable實現「虛擬」的策略(本項選擇如下圖所示)。還有奇怪的可空StartFinish變量遍佈代碼,在這種情況下...
  2. nullable IPlanningStrategy變量的情況下的任務,不能有計劃,只有當它被「提升」戰略的具體實例是Plannable

替代(1)應該是這樣的:

public class Task 
{ 
    public string Title { get; set; } 

    private IPlanningStrategy planningStrategy; 

    public Task() 
    { 
     planningStrategy = new NoPlanStrategy(); 
    } 

    public Task(IPlanningStrategy initialPlanningStrategy) 
    { 
     planningStrategy = initialPlanningStrategy; 
    } 

    public void SetPlanningStrategy(IPlanningStrategy newPlanningStrategy) 
    { 
     planningStrategy = newPlanningStrategy; 
    } 

    public DateTime? Start { get { return planningStrategy.Start; } } 
    public DateTime? Finish { get { return planningStrategy.Finish; } } 
} 


public interface IPlanningStrategy 
{ 
    public void CalculatePlan(); 
    public DateTime? Start { get; } 
    public DateTime? Finish { get; } 
} 

// "Dummy" strategy, used when Task does not have Planning behaviour 
// 
public class NoPlanStrategy : IPlanningStrategy 
{ 
    public void CalculatePlan() { } 
    public DateTime? Start { get { return null; } } 
    public DateTime? Finish { get { return null; } } 
} 



public class PlanStrategyA : IPlanningStrategy 
{ 
    private int parameter1; 
    private int parameter2; 
    private DateTime? start; 
    private DateTime? finish; 

    public PlanStrategyA(int p1, int p2) 
    { 
     parameter1 = p1; 
     parameter2 = p2; 
     start = finish = null; 
    } 

    public void CalculatePlan() 
    { 
     // ... uses parameter1 & parameter2 
     // ... to calculate start and finish 
    } 

    public DateTime? Start { get { return start; } } 

    public DateTime? Finish { get { return finish; } } 
} 

public class PlanStrategyB : IPlanningStrategy 
{ 
    public int parameter3; 

    // ... the rest is similar to PlanningStrategyA 

} 

現在我看到不同的**非常重要的**問題就在這裏。除了算法外,我的每一個具體的Strategy類都保留着,這當然是所有實現此算法的任務共享的附加參數,它們只屬於特定的Task

你能想象parameter1Effort(或者說,以完成任務所需要的剩餘小時數),並說parameter2LastDate(相當於限制日期,即最後允許的日期完成的任務)。這個參數自然屬於特定的Task,但只有當它實現這個特定的StrategyA

看來,實例化外部Task類策略沒有意義嗎?或者這應該是一些Factory方法的工作?

回答

0

IMO你在Task類中暴露了太多信息。我會做如下:

public class Task 
{ 
    // what is title being used for? 
    public string Title { get; set; } 

    private IPlanningStrategy planningStrategy; 

    public Task(IPlanningStrategy initialPlanningStrategy) 
    { 
     // Initialize it outside of constructor 
     if(initialPlanningStrategy == null) 
     { 
      throw new NullArgumentException(); // or return. 
     } 
     planningStrategy = initialPlanningStrategy; 
    } 

    public void CalculatePlan(){ 
     // check null and return. 
     planningStrategy.CalculatePlan(); 
    } 

} 

你的客戶不應該知道的開始,結束,我不認爲這是對算法的容器的責任。

此外,如果您的NoPlanStrategy沒有做任何事情,爲什麼介紹它。去掉它。

+0

感謝您的回答。如果可以具有可空的'Task.planninStrategy',那麼當然,我不需要「dummy」'NoStrategy'類,並且可以被刪除。關於第二點,我的客戶對'開始'和'完成'非常感興趣,因爲如果Task是Plannable,整個Planning的行爲就是向他們展示Start和Finish。但是,'Start'和'Finish'可以用與'Task.CalculatePlan()'類似的方式表示,即。檢查null並返回'開始/完成'如果不爲空? – buggy08

+0

是的,你可以做到這一點,如果你需要返回開始/完成把它們放在一個對象中,更改你的界面,以返回你的客戶期望滿足此合同的任何信息。相應地處理異常。 – DarthVader

+0

這裏有更多的問題:-)我剛剛擴展問題... – buggy08