2012-11-22 125 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