简体   繁体   English

在C#中如何正确实现命令设计模式?

[英]In C# how do I properly implement the Command Design Pattern?

I'm currently studying design patterns and I'm currently looking at the command pattern. 我正在研究设计模式,我目前正在研究命令模式。

Here is my current code: 这是我目前的代码:

// this is the receiver
class Calculator : IReceiver
{
    int x;
    int y;

    CommandOptions command;

    public Calculator(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

    public void SetAction(CommandOptions command)
    {
        this.command = command;
    }

    public int GetResult()
    {
        int result = 0;

        switch(this.command)
        {
            case CommandOptions.ADD:
                result = this.x + this.y;
                break;

            case CommandOptions.SUBTRACT:
                result = this.x - this.y;
                break;

            case CommandOptions.MULTIPLY:
                result = this.x * this.y;
                break;
        }

        return result;
    }
}

// command
abstract class Command
{
    protected IReceiver receiver;

    public Command(IReceiver receiver)
    {
        this.receiver = receiver;
    }

    public abstract int Execute();
}

class AddCommand : Command
{
    public AddCommand(IReceiver receiver) : base(receiver)
    {
    }

    public override int Execute()
    {
        reciever.SetAction(CommandOptions.ADD);
        return receiver.GetResult();
    }
}

enum CommandOptions
{
    ADD,
    SUBTRACT,
    MULTIPLY
}

interface IReceiver
{
    void SetAction(CommandOptions command);
    int GetResult();
}


class Program
{
    static void Main(string[] args)
    {
        IReceiver receiver = new Calculator(500, 25);

        //#Issue:The SetAction() method of the receiver is accessible.
        //receiver.SetAction(CommandOptions.ADD);
        receiver.SetAction(CommandOptions.MULTIPLY);
        Command command = null;

        Console.Write("Enter option 1-3: ");

        int commandOption = int.Parse(Console.ReadLine());

        switch(commandOption)
        {
            case 1:
                command = new AddCommand(receiver);
                break;

            case 2:
                command = new SubtractCommand(receiver);
                break;

            case 3:
                command = new MultiplyCommand(receiver);
                break;

            default:
                command = new AddCommand(receiver);
                break;
        }

        Console.WriteLine(command.Execute());
        Console.ReadKey();
    }
}

Notice that in my main method, I can access the SetAction method of the receiver which is capable of setting which command to use. 请注意,在我的main方法中,我可以访问接收器的SetAction方法,该方法能够设置要使用的命令。

My question is: does my implementation violate the purpose of the command pattern, and is my implementation wrong because I'm able to access it in my client code? 我的问题是:我的实现是否违反了命令模式的目的,并且我的实现是错误的,因为我能够在我的客户端代码中访问它? If so, how can I improve this implementation. 如果是这样,我该如何改进这种实现。

I took a shot of text-editing (ie haven't run it, expect syntax errors :) ) your code. 我拍了一些文本编辑(即没有运行它,期望语法错误:))你的代码。 Here's how I would model your problem. 这是我如何模拟你的问题。

Some points- 一些要点 -

1) Have the command do the action. 1)让命令执行操作。 In your case, you have command classes, but you calculator holds the logic for computation. 在您的情况下,您有命令类,但计算器保存计算逻辑。 Rather, encapsulate the command action within the command class itself 而是将命令操作封装在命令类本身中

2) I've put a factory to map the command option to the command and saved a few lines by removing the break s since I can return the command. 2)我已经将一个工厂将命令选项映射到命令,并通过删除break保存几行,因为我可以返回命令。

3) The IReceiver now holds the values which is passed on to Command. 3)IReceiver现在保存传递给Command的值。 In this case, since our operators are all binary, I've just used X and Y. Can be an array or any other complex type for other cases. 在这种情况下,由于我们的运算符都是二进制的,我只使用了X和Y.对于其他情况,可以是数组或任何其他复杂类型。

4) Enum isn't required, unless you absolutely want it. 4)除非你绝对需要,否则不需要枚举。

Edit On re-looking, I think an even better solution would be to not register the receiver with the commands, instead pass on the parameters while invoking the command. 编辑在重新审视时,我认为更好的解决方案是不使用命令注册接收器,而是在调用命令时传递参数。

//this is the receiver
class Calculator : IReceiver
{
    int y;
    int x;

    public Calculator(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

    public int Calculate(int commandOption)
    {
        Command command = new CommandFactory().GetCommand(commandOption);
        return command.Execute(x , y);
    }

}


//command
interface ICommand
{    
    int Execute(int x, int y);
}

class AddCommand : Command
{
    public override int Execute(int x, int y)
    {
        return x + y;
    }
}

class MultiplyCommand : Command
{
    public override int Execute(int x, int y)
    {
        return x * y;
    }
}

class SubtractCommand : Command
{
    public override int Execute(int x, int y)
    {
        return x - y;
    }
}

interface IReceiver
{
    int X {get; set;}
    int Y {get; set;}
    int Calculate(int commandOption);
}

public class CommandFactory
{
    public GetCommand(int commandOption)
    {
        switch(commandOption)
        {
            case 1:
                return new AddCommand();
            case 2:
                return new SubtractCommand();
            case 3:
                return new MultiplyCommand();
            default:
                return new AddCommand();
        }       
    }
}

class Program
{
    static void Main(string[] args)
    {
        IReceiver receiver = new Calculator(500, 25);
        //#Issue:The SetAction() method of the receiver is accessible.
        //receiver.SetAction(CommandOptions.ADD);

        //Receiver no longer exposes SetAction
        //receiver.SetAction(CommandOptions.MULTIPLY);
        Console.Write("Enter option 1-3: ");
        int commandOption = int.Parse(Console.ReadLine());

        Console.WriteLine(receiver.Calculate(commandOption));
        Console.ReadKey();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM