使用命令模式通过串行

时间:2017-04-10 12:35:00

标签: c# oop design-patterns command-pattern

我正在使用桌面应用程序,它应该通过串口发送和接收命令,并且我的同事正在编写固件。

我们设计了一个协议,其中命令类型由ASCII字母表示,每个命令类型可能包含一个有效负载(在命令类型之间是任意的,但对每种类型都是固定的),命令用方括号括起来。例如,我们有以下命令:

  • [S1234] - >从PC发送到设备以存储新的序列号,或从设备发送到PC以通知当前的序列号(类似于getter / setter命令);
  • [R] - 从PC发送到设备以询问“获取串行”命令;
  • [A12] - 从设备发送到PC以通知新的ADC读数;
  • [B] - 从PC发送到设备以要求电池充电;
  • `[B89] - 从设备发送到PC以通知电池充电;

所以我有一个接收和解析传入字节的类,每次成功解析一个命令时,都会引发一个事件,并带有以下暂定签名:

internal event EventHandler<SerialCommand> CommandReceived;

SerialCommand具有不同的子类型:BatteryCommand,AdcCommand,SerialCommand等。每个命令类型都与其各自的“字符代码”相关联。

我的问题是:客户端代码应该如何使用它?例如,我收到命令时的当前实现有一个带有硬编码字符的开关/案例,我发现它非常脆弱和丑陋:

    void CommandReceivedHandler(object sender, SerialCommand command)
    {
        switch (command.Code)
        {
            case 'A':
                int value= Convert.ToInt32(command.Value);
                _frameStreamer.AddFrame(new Frame<int>(new[] { value}));
                break;
            case 'B':
                BatteryLevel= (int)command.Value;
                break;
            case 'D':
                DoSomething((byte)command.Value);
                break;
            case 'S':
                SerialNumber = (int)command.Value;
                break;
        }           
    }

目前,这些“字符代码”分布在一堆类中,如果我需要更改给定的代码,我需要环顾四周(霰弹枪手术反模式)。

我需要做的是两件事:

  • 仅在非常命令中封装char代码,而不是客户端代码;
  • 在没有switch / case语句的情况下,优先在客户端(CommandReceived事件使用者)执行多种操作。

1 个答案:

答案 0 :(得分:2)

您可以尝试这样的事情:

public abstract class BaseCommand
{
    //Code not needed at all, because logic encapsulated into command
    //public char Code { get; set; }         
    public abstract void Action(IClient client);
}

public abstract class BaseCommand<T> : BaseCommand
{
    public T value { get; set; }
}

public class CommandA : BaseCommand<int>
{            
    public override void Action(IClient client)
    {        
        client.someInt = value * 2;
    }
}

public class CommandB : BaseCommand<string>
{
    public override void Action(IClient client)
    {
        client.someString = value.Trim();
    }
}

public interface IClient
{
    void CommandReceivedHandler(object sender, BaseCommand command);    
    int someInt { get; set; }
    string someString { get; set; }
}

public class Client : IClient
{
    public void CommandReceivedHandler(object sender, BaseCommand command)
    {
        command.Action(this);
    }

    public int someInt { get; set; }
    public string someString { get; set; }
}