C# 设计模式系列教程-命令模式

C# 设计模式系列教程-命令模式

什么是命令模式

命令模式是一种行为设计模式,它能把请求或操作封装起来,以便在不同上下文中进行参数化、延迟执行或支持撤销操作。命令模式把命令的发送者和接收者解耦,并且把命令操作封装成对象,这些对象可以用队列进行管理。

在命令模式中,任何对象都可以扮演“命令”的角色,唯一的要求是具备两项能力:

  1. 执行这个请求的操作。
  2. 把请求的接收者传递到执行的操作中。

通常情况下,会为每一种命令都创建一个类,这个类包含了接收者以及需要执行的方法。

命令模式的实现

命令模式的实现包含如下角色:

  • Command(抽象命令类):声明了一组用于执行操作的抽象方法,通常包含 Execute()Undo(),其中 Execute() 方法用于执行具体的命令操作,Undo() 方法用于撤销该操作。
  • ConcreteCommand(具体命令类):继承了 Command,实现了抽象方法,可以定义自己的逻辑来处理请求,并且可以保持一些额外的状态变量。
  • Invoker(调用者):会持有一个命令对象,并且在需要的时候,通过调用 Execute() 方法来触发命令。
  • Receiver(接收者):这个对象会实现具体的业务逻辑,并且能够完成 Command 对象需要执行的任何操作。此外,它们为 Command 对象提供了执行操作所需的任何上下文信息。

设计模式示例说明

示例一

假设我们现在有一个遥控器,它有若干个按钮可以控制电器。

我们可以使用命令模式来实现这个功能。

  1. 创建 Command 接口:
public interface ICommand
{
    void Execute();
    void Undo();
}

其中 ExecuteUndo 方法定义了我们需要的操作。

  1. 创建 Light 类作为接收者:
public class Light
{
    public void On() { Console.WriteLine("Light is on"); }
    public void Off() { Console.WriteLine("Light is off"); }
}

这个类表示了我们要控制的电器。

  1. 创建具体命令类 LightOnCommandLightOffCommand
public class LightOnCommand : ICommand
{
    private readonly Light _light;

    public LightOnCommand(Light light)
    {
        _light = light;
    }

    public void Execute()
    {
        _light.On();
    }

    public void Undo()
    {
        _light.Off();
    }
}

public class LightOffCommand : ICommand
{
    private readonly Light _light;

    public LightOffCommand(Light light)
    {
        _light = light;
    }

    public void Execute()
    {
        _light.Off();
    }

    public void Undo()
    {
        _light.On();
    }
}
  1. 创建 RemoteControl 类作为调用者:
public class RemoteControl
{
    private readonly ICommand[] _onCommands;
    private readonly ICommand[] _offCommands;

    public RemoteControl()
    {
        _onCommands = new ICommand[7];
        _offCommands = new ICommand[7];

        // 初始化命令数组
        for (var i = 0; i < 7; i++)
        {
            _onCommands[i] = new NoCommand();
            _offCommands[i] = new NoCommand();
        }
    }

    public void SetCommand(int slot, ICommand onCommand, ICommand offCommand)
    {
        _onCommands[slot] = onCommand;
        _offCommands[slot] = offCommand;
    }

    public void OnButtonWasPushed(int slot)
    {
        _onCommands[slot].Execute();
    }

    public void OffButtonWasPushed(int slot)
    {
        _offCommands[slot].Execute();
    }
}

这个类实例化一个 ICommand 数组,同时实现了 SetCommandOnButtonWasPushedOffButtonWasPushed 方法。当执行某个命令时,会调用相应的 Execute 方法。

  1. 编写测试代码:
var remoteControl = new RemoteControl();

var light = new Light();
var lightOnCommand = new LightOnCommand(light);
var lightOffCommand = new LightOffCommand(light);

remoteControl.SetCommand(0, lightOnCommand, lightOffCommand);

remoteControl.OnButtonWasPushed(0); // Light is on
remoteControl.OffButtonWasPushed(0); // Light is off

通过测试代码的执行,我们可以实现控制电器打开和关闭的功能。

示例二

我们现在来实现一个简单的遥控器,它有两个按钮:一个按钮用来开门,另一个按钮用来关门。同时,我们需要实现撤销功能,可以撤销最后一个操作。

  1. 创建 Door 类作为接收者:
public class Door
{
    private bool _isOpen;

    public bool IsOpen() => _isOpen;

    public void Open()
    {
        Console.WriteLine("Door is open");
        _isOpen = true;
    }

    public void Close()
    {
        Console.WriteLine("Door is closed");
        _isOpen = false;
    }
}

这个类表示了我们要控制的门。

  1. 创建具体命令类 OpenDoorCommandCloseDoorCommand
public class OpenDoorCommand : ICommand
{
    private readonly Door _door;

    public OpenDoorCommand(Door door)
    {
        _door = door;
    }

    public void Execute()
    {
        _door.Open();
    }

    public void Undo()
    {
        _door.Close();
    }
}

public class CloseDoorCommand : ICommand
{
    private readonly Door _door;

    public CloseDoorCommand(Door door)
    {
        _door = door;
    }

    public void Execute()
    {
        _door.Close();
    }

    public void Undo()
    {
        _door.Open();
    }
}
  1. 创建 SimpleRemoteControl 类作为调用者:
public class SimpleRemoteControl
{
    private ICommand _lastCommand;

    public void SetCommand(ICommand command)
    {
        _lastCommand = command;
    }

    public void ButtonWasPressed()
    {
        _lastCommand.Execute();
    }

    public void UndoButtonWasPressed()
    {
        _lastCommand.Undo();
    }
}

这个类实现了 SetCommandButtonWasPressedUndoButtonWasPressed 方法。同时,还用一个成员变量 _lastCommand 记录最后一次执行的命令。

  1. 编写测试代码:
var door = new Door();
var openCommand = new OpenDoorCommand(door);
var closeCommand = new CloseDoorCommand(door);

var remote = new SimpleRemoteControl();

remote.SetCommand(openCommand);
remote.ButtonWasPressed(); // Door is open
remote.UndoButtonWasPressed(); // Door is closed

remote.SetCommand(closeCommand);
remote.ButtonWasPressed(); // Door is closed
remote.UndoButtonWasPressed(); // Door is open

通过测试代码的执行,我们可以实现开门、关门以及撤销功能。

总结

命令模式能够把一个请求封装为一个对象,并且能够进行动态地参数化、队列化、简单的请求或撤销。通过使用这个模式,我们可以将发出命令的对象和执行命令的对象进行解耦。同时,命令模式还能够维护一组对象,这些对象能够随时添加、删除或替换。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C# 设计模式系列教程-命令模式 - Python技术站

(0)
上一篇 2023年5月31日
下一篇 2023年5月31日

相关文章

  • C#的String和StringBuilder详解

    C#的String和StringBuilder详解 String和StringBuilder的区别 在C#中,字符串(String)是一个不可变的类,一旦被创建,其内容就无法修改,任何对字符串的操作都会返回一个新的字符串对象。而StringBuilder是一个可变的类,能够修改其内容而不创建新的对象,从而提高了字符串操作的效率。 String的使用 Stri…

    C# 2023年5月31日
    00
  • .Net Core2.1 WebAPI新增Swagger插件详解

    .Net Core2.1 WebAPI新增Swagger插件详解 Swagger是一种API文档工具,它可以自动生成API文档,并提供一个交互式的UI界面,方便开发人员测试API。在.Net Core2.1中,我们可以使用Swagger插件来自动生成API文档。本攻略将详细介绍如何使用Swagger插件。 安装Swagger插件 我们可以使用以下命令来安装S…

    C# 2023年5月17日
    00
  • asp.net 读取并修改config文件实现代码

    ASP.NET 是一个非常受欢迎的 Web 应用程序开发框架,其配置文件 config 文件是应用程序的核心之一,配置文件存储了应用程序运行所需的信息。我们可以通过读取和修改 config 文件来完成应用程序的配置。在本文中,我将详细讲解如何通过 ASP.NET 读取并修改 config 文件的方法。 准备工作 首先,我们需要准备好目标 config 文件。…

    C# 2023年5月31日
    00
  • C#实现的Windows剪贴板监视器功能实例【附demo源码下载】

    C#实现的Windows剪贴板监视器功能实例 前言 剪贴板是我们在使用电脑时几乎必然会用到的功能之一,而剪贴板监视器的作用就是拦截剪贴板的相关操作,我们可以通过监视剪贴板来实现一些功能,如:自动翻译剪贴板内容等。在本文中,将通过C#实现Windows剪贴板监视器的功能,并附带Demo源码以及详细讲解。 实现剪贴板监视器 1. 创建项目 首先,我们需要创建一个…

    C# 2023年6月8日
    00
  • unity android设备上查看log输出方式

    下面我就来为您详细讲解在Unity Android设备上查看Log输出方式的完整攻略。 1. Unity Android设备上查看Log输出方式 在Unity Android设备上查看Log输出可以通过两种方式实现,一种是使用Android SDK提供的logcat工具,另一种是使用Unity控制台。 1.1 使用Android SDK提供的logcat工具…

    C# 2023年5月15日
    00
  • C#使用JavaScriptSerializer序列化时的时间类型处理

    说明:本文主要介绍在 C# 中使用 JavaScriptSerializer 序列化时,如何处理时间类型。提供两种示例说明。 问题 在使用 C# 中的 JavaScriptSerializer 序列化对象时,如果包含时间类型,会遇到时间格式序列化异常的问题。而我们通常需要使用特定格式来序列化时间类型,例如 ISO 格式或自定义格式。 解决方法 方法一:通过自…

    C# 2023年5月31日
    00
  • C#备忘录模式(Memento Pattern)实例教程

    C#备忘录模式(Memento Pattern)实例教程 备忘录模式(Memento Pattern)是一种行为型设计模式,它允许将一个对象的内部状态保存到一个外部的备忘录对象中,从而可以在需要时将对象恢复到先前的状态。在本篇教程中,我们将介绍C#中备忘录模式的使用方法和实现步骤,并提供两个示例说明。 示例一:备忘录模式的基本使用 步骤一:创建备忘录类 首先…

    C# 2023年6月8日
    00
  • C# 7.0 新特性1之基于Tuple的“多”返回值方法

    当我们在编写方法时需要返回多个值时,往往可以将这些值封装成一个类或结构体返回,但是如果只是为了返回几个简单的值,这样会显得过于繁琐。而C#7.0新增了一种基于Tuple的多返回值方法,可以让我们更方便地返回多个值。 Tuple 简介 Tuple(元组)是一种简单的数据结构,它可以轻松地封装一组不同类型的值,并使用点符号来访问每个值。Tuple 最初是在 .N…

    C# 2023年5月15日
    00
合作推广
合作推广
分享本页
返回顶部