在C#中如何正确实现Command Design Pattern? [英] In C# how do I properly implement the Command Design Pattern?

查看:116
本文介绍了在C#中如何正确实现Command Design Pattern?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



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

  //这是接收者
类计算器:IReceiver
{
int x;
int y;

CommandOptions命令;

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

返回结果;
}
}

//命令
抽象类命令
{
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();
}
}

枚举CommandOptions
{
添加,
SUBTRACT,
MULTIPLY
}

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


类程序
{
static void Main(string [] args)
{
IReceiver receiver = new计算器(500,25);

//#问题:接收器的SetAction()方法是可访问的。
//receiver.SetAction(CommandOptions.ADD);
receiver.SetAction(CommandOptions.MULTIPLY);
命令command = null;

Console.Write(输入选项1-3:);

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

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

案例2:
command = new SubtractCommand(receiver);
break;

案例3:
command = new MultiplyCommand(receiver);
break;

默认值:
command = new AddCommand(receiver);
break;
}

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

请注意,在我的主要方法中,我可以访问

我的问题是:我的实现违反命令模式的目的,而且我的实现是错误的,因为我可以在我的客户端代码中访问它?如果是这样,我如何改进这个实现。

解决方案

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



有些点 -



1)命令执行操作。在你的情况下,你有命令类,但是你的计算器拥有计算的逻辑。相反,将命令操作封装在命令类本身中



2)我已经把工厂映射到该命令的命令选项并保存了几行,通过删除 break s,因为我可以返回命令。



3)IReciever现在保存传递给的值命令。在这种情况下,由于我们的运算符都是二进制的,所以我刚刚使用X和Y.可以是其他情况下的数组或其他复杂类型。



4)枚举是不需要的,除非你绝对想要它。



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

  //这是reciever 
class Calculator:IReciever
{
int y;
int x;

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

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

}


//命令
接口ICommand
{
int执行(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)
{
返回x * y;
}
}

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

接口IReciever
{
int X {get; set;}
int Y {get; set;}
int Calculate(int commandOption);
}

public class CommandFactory
{
public GetCommand(int commandOption)
{
switch(commandOption)
{
案例1:
返回新的AddCommand();
案例2:
返回新的SubtractCommand();
案例3:
返回新的MultiplyCommand();
默认值:
返回新的AddCommand();
}
}
}


类程序
{
static void Main(string [] args)
{
IReciever reciever = new Calculator(500,25);
//#问题:接收者的SetAction()方法是可访问的。
//reciever.SetAction(CommandOptions.ADD);

//收件人不再公开SetAction
//reciever.SetAction(CommandOptions.MULTIPLY);
Console.Write(输入选项1-3:);
int commandOption = int.Parse(Console.ReadLine());


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


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.

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 (i.e 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. 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 breaks since I can return the command.

3) The IReciever now holds the values which is passed on to 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.

4) Enum isn't required, unless you absolutely want it.

Edit On re-looking, I think an even better solution would be to not register the reciever with the commands, instead pass on the parameters while invoking the command.

//this is the reciever
class Calculator : IReciever
{
    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 IReciever
{
    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)
    {
        IReciever reciever = new Calculator(500, 25);
        //#Issue:The SetAction() method of the reciever is accessible.
        //reciever.SetAction(CommandOptions.ADD);

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


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

这篇关于在C#中如何正确实现Command Design Pattern?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆