C# - 设计模式 - 命令模式


命令模式

问题场景

一个遥控器有1个插槽,插槽对应了两个按钮,一个on,一个off,插槽可以临时插入一个命令,当点击遥控器的on或off按钮时就会调用命令,命令调用某个对象的方法来执行具体的操作。

总结模式

一个对象只需存储命令和执行命令,它不需要知道命令执行的是什么逻辑,它只关心命令的存储和调用,具体执行的是什么操作应该由命令对象自己去和目标对象沟通。这个模式可以方便的执行命令,今后有新需求,就可以创建新的命令,只要该命令符合命令的抽象,通过把新命令注入到字典中就能够得到执行。

示例代码

先敲出下面的代码,而不要去设计具体的类型,先考虑可能的调用代码,再设计具体的类型

//遥控器有插槽和按钮
//插槽:可以插入一个命令,命令作为遥控器的属性被存取
//按钮:执行命令,用遥控器的ButtonClick模拟按钮的点击
//执行命令可以控制某个电器装置
RemoteControl remoteControl = new RemoteControl( ); //遥控器

//电灯提供on和off方法
Light light = new Light( );

//命令,持有对电灯的引用,所以可以调用电灯的on和off方法
LightOnCmd lightOnCmd = new LightOnCmd( light );
LightOffCmd lightOffCmd = new LightOffCmd( light );

remoteControl.OnCmd = lightOnCmd; //遥控器持有开灯的命令
remoteControl.OffCmd = lightOffCmd; //遥控器持有关灯的命令
remoteControl.ButtonOnClick( ); //触发遥控器上的On按钮
remoteControl.ButtonOffClick( );//触发遥控器上的Off按钮

有了以上的思考,现在开始具体的类型结构设计

//命令的抽象
public interface ICommand
{
    void Execute( );
}

//开灯命令的具象
public class LightOnCmd : ICommand
{
    private Light Light;
    public LightOnCmd( Light light ) { Light = light; }
    public void Execute( ) { Light.On( ); }
}

//关灯命令的具象
public class LightOffCmd : ICommand
{
    private Light Light;
    public LightOffCmd( Light light ) { Light = light; }
    public void Execute( ) { Light.Off( ); }
}

//灯对象提供开关方法,供命令调用
public class Light
{
    public void On( ) { Console.WriteLine( "灯亮" ); }
    public void Off( ) { Console.WriteLine( "灯灭" ); }
}

//遥控器
public class RemoteControl
{
    public ICommand OnCmd; //通过属性注入命令
    public ICommand OffCmd; //通过属性注入命令

    public void ButtonOnClick( ) { OnCmd.Execute( ); }
    public void ButtonOffClick( ) { OffCmd.Execute( ); }
}

改进版:一次注入多个命令

//命令的抽象
public interface ICommand
{
    void Execute( );
}

//开灯命令的具象
public class LightOnCmd : ICommand
{
    private Light Light;
    public LightOnCmd( Light light ) { Light = light; }
    public void Execute( ) { Light.On( ); }
}

//关灯命令的具象
public class LightOffCmd : ICommand
{
    private Light Light;
    public LightOffCmd( Light light ) { Light = light; }
    public void Execute( ) { Light.Off( ); }
}

//灯对象提供开关方法,供命令调用
public class Light
{
    public void On( ) { Console.WriteLine( "灯亮" ); }
    public void Off( ) { Console.WriteLine( "灯灭" ); }
}

//遥控器
public class RemoteControl
{
    public Dictionary<string, ICommand> Cmds;
    private ICommand Cmd;
    //通过构造函数注入一组命令
    public RemoteControl( Dictionary<string, ICommand> cmds )
    {
        Cmds = cmds;
    }

    public void ButtonOnClick( string cmdOnKey )
    {
        Cmd = Cmds[cmdOnKey];
        if (Cmd != null)
        {
            Cmd.Execute( );
        }
    }
    public void ButtonOffClick( string cmdOffKey )
    {
        Cmd = Cmds[cmdOffKey];
        if (Cmd != null)
        {
            Cmd.Execute( );
        }
    }
}

public class Programe
{
    static void Main( string[] args )
    {
        Light light = new Light( );
        Dictionary<string, ICommand> cmds = new Dictionary<string, ICommand>
    {
        { "LightOn", new LightOnCmd(light) },
        { "LightOff", new LightOffCmd(light) }
    };
        RemoteControl remoteControl = new RemoteControl( cmds );
        remoteControl.ButtonOnClick( "LightOn" );
        remoteControl.ButtonOffClick( "LightOff" );
    }
}

命令宏:当按下一个On按钮,可以打开电灯、再打开恒温器和电视机,这一组宏指令可以通过定义一个宏命令类来完成,具体略。

C# - 设计模式目录