2012-02-09 35 views
1

我想实现一个命令模式。我有以下几点:实现命令模式和多态性

public class State 
{ 
    public int Number { get; set; } 

    public void Execute(IAction action) 
    { 
     if (action.IsValid(this)) 
      action.Apply(this); 
    }    
} 

public interface IAction 
{ 
    bool IsValid(State state); 
    void Apply(State state); 
}  

public class ActionSet5IfZero : IAction 
{ 

    public bool IsValid(State state) 
    { 
     if (state.Number == 0) 
      return true; 
     else 
      return false; 
    } 

    public void Apply(State state) 
    { 
     state.Number = 5; 
    } 
} 

而且程序:

static void Main(string[] args) 
{ 
    State s = new State(); 
    s.Execute(new ActionSet5IfZero()); 
} 

按预期工作。我的问题开始,当我想延长State类:

public class ExtendedState : State 
{ 
    public int Number2 { get; set; } 
} 

现在的动作必须在ExtendedState应用更改。所以我想我会创建具有采取ExtendedState作为参数的两个附加的功能扩展行动:

public class ExtendedActionSet5IfZero : IAction 
{ 

    public bool IsValid(State state) 
    { 
     throw new NotImplementedException(); 
    } 

    public void Apply(State state) 
    { 
     throw new NotImplementedException(); 
    } 

    public bool IsValid(ExtendedState state) 
    { 
     if (state.Number == 0 && state.Number2 == 0) 
      return true; 
     else 
      return false; 
    } 

    public void Apply(ExtendedState state) 
    { 
     state.Number = 5; 
     state.Number2 = 5; 
    } 
} 

这事我已经不喜欢,因为实现接口的功能变得多余。此外,我需要在我的ExtendedState中创建一个新的Execute函数,它使用新类型而不是IAction(否则未实现的函数会被调用)。

我相信它可以用一个很好的OO方式完成。你能帮我吗?其目的是创建一个可扩展的State类和IAction接口(可能甚至是通用的,我不知道),所以我可以扩展State,但仍然是通用功能,无需额外编码。

回答

0

你可以使用泛型:

interface IAction<TState> where TState: State 
{ 
    bool IsValid(TState state); 
    void Apply(TState state); 
} 
+1

我以前试过这个。问题是当我扩展State类并尝试重用Execute函数时。 IAction 类型与IAction 无关,我得到异常。 – 2012-02-09 17:00:30

0

如何添加StateContainer到国家和行动:

public class ValidatingStateContainer<TState, TAction> : IStateContainer<TState, TAction> { 

    public ValidatingStateContainer(TState state) { 
     State = state; 
    } 

    public TState State { get; private set; } 

    public void Execute(TAction action) 
    { 
     if (action.IsValid(this)) 
      action.Apply(State); 
    } 
} 

public class ActionSet5IfZero : IAction<NumberState> 
{ 
    public boolean IsValid(NumberState state) 
    { 
     if (state.Number == 0) 
      return true; 
     else 
      return false; 
    } 

    public void Apply(NumberState state) 
    { 
     state.Number = 5; 
    } 
} 

public class ExtendedActionSet5IfZero : ActionSet5IfZero, IAction<TwoNumberState> 
{ 
    public boolean IsValid(TwoNumberState state) 
    { 
     if (base.IsValid(state) && state.Number2 == 0) 
      return true; 
     else 
      return false; 
    } 

    public void Apply(TwoNumberState state) 
    { 
     base.Apply(state); 
     state.Number2 = 5; 
    } 
} 

public class NumberState : IState { 
    public int Number { get; set; } 
} 

public class TwoNumberState : NumberState { 
    public int Number2 { get; set; } 
} 
1

,你可以:

public interface IStateContainer<TState, TAction> where TState : IState where TAction : IAction<TState> { 
    public TState State; 
    public void Execute(TAction action); 
} 

public interface IState { } 

public interface IAction<TState> where TState : IState { 
    bool IsValid(TState state); 
    void Apply(TState state); 
} 

然后你原来的类可以被替换添加一个虚拟的SetNumber方法到状态

public class State 
{ 
    public int Number { get; set; } 

    public virtual void SetNumber(int n) 
    { 
     Number = n; 
    } 

    public void Execute(IAction action) 
    { 
     if (action.IsValid(this)) 
      action.Apply(this); 
    }    
} 

在扩展状态下,你orverride它

public class ExtendedState : State { 
    public int Number2 { get; set; } 

    public orverride void SetNumber(int n) 
    { 
     base.SetNumber(n); 
     Number2 = n; 
    } 
} 

的行动将被这样

public void Apply(State state)   
{ 
    state.SetNumber(5);   
}  

编辑实现:

有关声明号码

什么作为数组?

public class State 
{ 
    public int[] Numbers { get; private set; } 

    public State() 
    { 
     Numbers = new int[1]; 
    } 

    ... 
} 

的行动,那么这是否

public void Apply(State state)   
{ 
    for (int i = 0; i < state.Numbers.Length; i++) { 
     state.Numbers[i] = 5; 
    } 
} 

ExtendedState的构造函数初始化Numbers

Numbers = new int[2]; 

此外,你可能对单数性质

public int Number { 
    get { return Numbers[0]; } 
    set { Numbers[0] = value; } 
} 

public int Number2 { 
    get { return Numbers[1]; } 
    set { Numbers[1] = value; } 
} 
+0

hanks奥利维尔回应。问题是我有无数的动作,因此*命令模式*。你的解决方案不适合我的情况......我可以做一些关于Execute命令的虚拟化吗? – 2012-02-09 16:54:54