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日

相关文章

  • 代码自动生成工具ASP.NET Maker 2019安装及激活教程(附替换补丁+软件下载)

    ASP.NET Maker 2019是一款用于生成ASP.NET Core MVC、Web API、Web应用程序和移动应用程序的代码自动生成工具。以下是安装和激活教程: STEP 1:下载软件 首先需要从官方网站https://www.hkvstore.com/aspmaker下载ASP.NET Maker 2019安装包。 STEP 2:安装软件 下载完…

    C# 2023年5月31日
    00
  • C#通过属性名称获取(读取)属性值的方法

    获取C#对象的属性值通常可以使用对象的属性名称来实现。在 C# 中,属性名称是一个字符串,可以在运行时利用反射机制获取对象的属性信息,并通过属性名称获取属性值。 首先,在 C# 中利用反射机制获取对象的属性信息,可以通过以下步骤来实现: 获取对象的类型信息:使用Type.GetType或typeof关键字获取对象类型信息,例如: csharp Type ty…

    C# 2023年5月31日
    00
  • WinForm实现鼠标拖动控件跟随效果

    为了实现WinForm中的鼠标拖动控件跟随效果,我们需要使用下述步骤: 1. 获取鼠标位置 鼠标在界面上移动时,我们需要获取其当前位置。可以通过下面的代码来获取: private void panel1_MouseMove(object sender, MouseEventArgs e) { Point point = Control.MousePositi…

    C# 2023年6月1日
    00
  • 如何在C#9 中使用static匿名函数

    在C# 9中,我们可以使用静态匿名函数来编写更优雅、简介的代码。 静态匿名函数的定义 在C#9中,我们可以使用静态匿名函数定义一个函数,格式如下: delegate [return-type] identifier([parameter-list]); 其中,delegate关键字表示这是一个函数声明,return-type 表示返回值类型,identifi…

    C# 2023年6月6日
    00
  • C# 委托的三种调用示例(同步调用 异步调用 异步回调)

    C# 委托是一种特殊的数据类型,它允许在运行时将方法作为参数传递给其他方法,也可以作为返回值,这在异步编程中很有用。本篇攻略将重点讲解 C# 委托的三种调用示例:同步调用、异步调用和异步回调。 同步调用 同步调用是指调用一个方法时,程序会一直等待该方法执行完毕并返回结果后再继续执行下一步操作。这种调用方式是最常见的,也是最简单的方式。 以下代码示例展示了委托…

    C# 2023年6月1日
    00
  • .NET 中配置从xml转向json方法示例详解

    以下是关于在.NET中配置从XML转向JSON方法示例详解的攻略: 1. 问题描述 在.NET中,我们可以使用XML或JSON格式来配置应用程序。在某些情况下,我们可能需要将XML配置转换为JSON格式。本攻略将介绍如何在.NET中将XML配置转换为JSON。 2. 解决方案 在.NET中,我们可以使用System.Xml.Linq和System.Text.…

    C# 2023年5月12日
    00
  • C#/VB.NET 自定义PPT动画路径的步骤

    C#/VB.NET 可以通过程序动态生成 PowerPoint(PPT)文档,并自定义 PPT 动画路径。下面是具体的步骤: 1. 创建 PowerPoint 应用程序对象 首先需要创建一个 PowerPoint 应用程序对象,可以通过调用 COM 互操作库中的 PowerPoint.Application 类来完成: using PowerPoint = …

    C# 2023年6月3日
    00
  • C# 字节数组、各进制字符串数据互转

    前言 日常开发过程中,格式转换是必不可少的重要环节,经常是十进制转十六进制、十六进制转byte数组又转换回来来回转换,最然进制转换很基础同时 C# 也提供了很多直接方便进行格式转换的方法,但是封装一个工具类会方便很多,不用每次都手写代码逻辑,之前一直都是简单的自己写,稍复杂的就用前辈写好的直接调用,这次自己写一个。 简单的定义为一行代码完事,多一行都不写?。…

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