实现命令模式和多态性

发布于 2025-01-04 14:47:50 字数 1765 浏览 0 评论 0原文

我想实现一个命令模式。我有以下内容:

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 (否则将调用未实现的函数)。

我确信它可以以一种很好的面向对象的方式完成。你能帮我一下吗?目的是创建一个可扩展的 State 类和 IAction 接口(甚至可能是通用的,我不知道),因此我可以扩展 State,但保留通用功能,而无需额外编码。

I want to implement a command pattern. I have the following:

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;
    }
}

And the program:

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

That works as expected. My problem begins, when I would like to extend the State class:

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

Now the action must apply changes on ExtendedState. So I thought I would create extended action that has two additional functions that take ExtendedState as a parameter:

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;
    }
}

This is something I already do not like because the functions that implement the interface become redundant. Moreover I need to create a new Execute function in my ExtendedState that utilizes the new type and not IAction (otherwise not implemented functions get called).

I am sure it can be done in a nice OO way. Can you help me out? The aim is to create an extensible State class and IAction interface (maybe even generic, I do not know), so I can extend the State but remain the generic functionality without additional coding.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

岁吢 2025-01-11 14:47:50

您可以添加一个虚拟的 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); 
    }             
} 

在扩展状态中您或验证它

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);        
}    

编辑一样实现:

将 Number 声明为数组怎么样?

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; }
}

You could add a virtual SetNumber method to state

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); 
    }             
} 

In the extended state you orverride it

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

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

The action would then be implemented like this

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

EDIT:

What about declaring Number as array?

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

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

   ...
}

The action then does this

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

The constructor of ExtendedState would initialize Numbers with

Numbers = new int[2];

In addition, you could have properties for the single numbers

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

and

public int Number2 { 
    get { return Numbers[1]; }
    set { Numbers[1] = value; }
}
梦罢 2025-01-11 14:47:50

您可以使用泛型:

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

You could use generics:

interface IAction<TState> where TState: State
{
    bool IsValid(TState state);
    void Apply(TState state);
}
倾城花音 2025-01-11 14:47:50

将 StateContainer 添加到 State 和 Action 怎么样:

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);
}

然后你原来的类可以替换为:

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; }
}

How about adding StateContainer to State and Action:

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);
}

Then your original classes can be replaced with:

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; }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文