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

时间:2013-03-24 15:30:53

标签: c# design-patterns command-pattern

我目前正在研究设计模式,我目前正在研究命令模式。

这是我目前的代码:

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

请注意,在我的main方法中,我可以访问接收器的SetAction方法,该方法能够设置要使用的命令。

我的问题是:我的实现是否违反了命令模式的目的,并且我的实现是错误的,因为我能够在我的客户端代码中访问它?如果是这样,我该如何改进这种实施。

1 个答案:

答案 0 :(得分:9)

我拍了一段文字编辑(即没有运行它,期望语法错误:))你的代码。以下是我如何为您的问题建模。

有些观点 -

1)让命令执行操作。在您的情况下,您有命令类,但计算器保存计算逻辑。相反,将命令操作封装在命令类本身

2)我已经将一个工厂将命令选项映射到命令,并通过删除break来保存几行,因为我可以返回命令。

3)IReceiver现在保存传递给Command的值。在这种情况下,由于我们的运算符都是二进制的,我只使用了X和Y.对于其他情况,可以是数组或任何其他复杂类型。

4)除非你绝对需要,否则不需要枚举。

修改 在重新审视时,我认为更好的解决方案是不使用命令注册接收器,而是在调用命令时传递参数。

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