🏆 作者简介,愚公搬代码 🏆《头衔》:华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,阿里云专家博主,腾讯云优秀博主,掘金优秀博主,51CTO博客专家等。 🏆《近期荣誉》:2022年CSDN博客之星TOP2,2022年华为云十佳博主等。
🏆《博客内容》:.NET、Java、Python、Go、Node、前端、IOS、Android、鸿蒙、Linux、物联网、网络安全、大数据、人工智能、U3D游戏、小程序等相关领域知识。
🏆🎉欢迎 👍点赞✍评论⭐收藏
设计模式(Design Pattern)是软件开发领域的宝贵经验,是多人反复借鉴和广泛应用的代码设计指导。它们是一系列经过分类和归纳的代码组织方法,旨在实现可重用性、可维护性和可理解性。使用设计模式,我们能够编写高质量的代码,使其更易于他人理解,并提供了代码可靠性的保证。
毫无疑问,设计模式对个人、团队和整个系统都带来了显著的益处。它们将代码开发提升到工程化水平,为软件工程构建提供了坚实的基础,就如同大厦的一块块精巧的砖石一样。在项目中明智地应用设计模式可以完美地解决各种复杂问题。每种设计模式都有相应的原理和最佳实践,它们描述了我们日常开发中不断遇到的问题,以及这些问题的核心解决方法。正是因为这种实用性和通用性,设计模式才能在软件开发中广泛地得以应用。设计模式是构建稳健、可扩展和可维护软件的关键工具,为开发者们提供了解决问题的智慧和指导。
当谈及命令模式时,我们涉及到一种行为型设计模式,它的目的在于将一个请求封装成一个对象,从而能够以不同的请求来参数化客户端。
具体来说,在这种设计模式中,请求会被包裹成一个命令对象,并传递给调用者。调用者会寻找适合处理该命令的对象,并将命令传递给相应的对象以执行。
这种模式的优势在于可以实现松耦合,允许将请求的发起者与请求的执行者解耦。这也使得可以将多个命令排队、延迟执行或者撤销。
需要注意的是,命令模式适用于各种场景,尤其在需要对请求进行排队、记录日志、撤销或重做等情况下十分有用。同时,它也为系统的扩展提供了便利,能够方便地添加新的命令和处理方式。
在命令模式(Command Pattern)中,抽象命令(Command)是一个关键概念,它具有以下作用:
抽象命令在命令模式中充当了请求的中介,将请求的发起者和接收者解耦,同时支持一系列附加功能,如撤销、重做、队列和事务等。这使得命令模式成为一种强大的设计模式,可用于多种场景,提高了系统的灵活性和可维护性。
在命令模式(Command Pattern)中,具体命令(Concrete Command)是一种具体的命令对象,它实现了抽象命令(Command)接口,并且负责将一个具体的请求绑定到接收者(执行者)上,以执行该请求。以下是具体命令的概念和作用:
execute
)和撤销(undo
)操作。execute
)方法,该方法包含了实际的操作逻辑。当具体命令的 execute
方法被调用时,它会将请求委派给接收者来执行请求的实际操作。undo
)方法,允许系统能够撤销之前执行的操作。这对于实现撤销和重做功能非常有用,以及处理事务性操作。具体命令是命令模式的核心组成部分,它负责将请求与接收者解耦,并提供了执行和撤销请求的方法。通过使用具体命令,可以实现灵活的命令调用和支持一系列与请求相关的附加功能,如撤销、队列、事务等。这使得命令模式非常有用,特别是在需要构建可扩展和可维护的系统时。
在命令模式(Command Pattern)中,接收者(Receiver)是负责执行与请求相关的实际操作的对象。它具体执行了命令对象所代表的请求。以下是接收者的概念和作用:
execute
方法被调用时,它通常会调用接收者的一个或多个方法来执行请求的实际操作。接收者在命令模式中扮演着关键角色,它负责执行与命令相关的实际操作,为命令模式提供了强大的执行能力。通过将接收者与命令对象解耦,命令模式可以在不改变发送者或接收者代码的前提下,灵活地新增、修改或删除命令。这提高了系统的灵活性和可维护性,使得命令模式成为一种强大且广泛使用的设计模式。
在命令模式(Command Pattern)中,调用者(Invoker)是一个对象,负责将具体的命令对象与其执行者(接收者)连接起来,并在需要时触发命令的执行。以下是调用者的概念和作用:
execute
方法来实现。调用者在命令模式中充当了一个协调者的角色,它负责管理命令对象并触发它们的执行。通过使用调用者,命令模式能够实现请求的发送者与接收者的解耦,支持一系列附加功能,如撤销、重做、批处理和队列。这提高了系统的灵活性和可维护性,使得命令模式成为一种有力的设计模式。
命名空间CommandPattern中包含Command基类、发票开具命令类CreateCommand、发票作废命令类CancelCommand、发票打印命令类PrintCommand、命令参数基类CommandArgs、发票开具命令参数类CommandArgs、发票作废命令参数类CancelArgs、发票打印命令参数类PrintArgs、接收者类Receiver和调用者类Invoker。本命尝试通过客户端调用不同的参数化发票命令来使调用者调用不同的功能。
public abstract class Command {
protected Receiver _receiver = null;
protected CommandArgs _commandArgs = null;
public Command(Receiver receiver, CommandArgs commandArgs) {
this._receiver = receiver;
this._commandArgs = commandArgs;
}
public abstract void Action();
}
抽象命令基类,包含Action动作执行命令,并且维持对接受者和命令参数的引用。
public class CreateCommand : Command {
public CreateCommand(Receiver receiver, CommandArgs commandArgs)
: base(receiver, commandArgs) {
}
public override void Action() {
_receiver.CommandArgs = _commandArgs;
(_receiver as CreateReceiver)?.CreateInvoice();
}
}
这是发票开具命令,由于基类维持了对调用者的引用,所以在Action方法中通过调用CreateInvoice方法来开具一张发票。
public class CancelCommand : Command {
public CancelCommand(Receiver receiver, CommandArgs commandArgs)
: base(receiver, commandArgs) {
}
public override void Action() {
_receiver.CommandArgs = _commandArgs;
(_receiver as CancelReceiver)?.CancelInvoice();
}
}
这是发票作废命令,由于基类维持了对调用者的引用,所以在Action方法中通过调用CancelInvoice方法来作废一张发票。
public class PrintCommand : Command {
public PrintCommand(Receiver receiver, CommandArgs commandArgs)
: base(receiver, commandArgs) {
}
public override void Action() {
_receiver.CommandArgs = _commandArgs;
(_receiver as PrintReceiver)?.PrintInvoice();
}
}
这是发票打印命令,由于基类维持了对调用者的引用,所以在Action方法中通过调用PrintInvoice方法来打印一张发票。
public class CommandArgs {
public string InvoiceType { get; set; }
}
public class CreateArgs : CommandArgs {
public DateTime BillingDate { get; set; }
}
public class CancelArgs : CommandArgs {
public string InvoiceCode { get; set; }
public int InvoiceNumber { get; set; }
public string CancelReason { get; set; }
public string CancelMan { get; set; }
public DateTime CancelDate { get; set; }
}
public class PrintArgs : CommandArgs {
public string InvoiceCode { get; set; }
public int InvoiceNumber { get; set; }
}
参数化的命令参数基类CommandArgs和它的3个具体实现类。实际开发过程中可以将参数化命令信息封装在具体命令类中,本例为了更好的扩展性,将参数化命令信息抽象出来。
public class Invoker {
private Command _command = null;
public Invoker(Command command) {
this._command = command;
}
public void Execute() {
_command.Action();
}
}
调用者类Invoker,实际开发中这个应为具体的调用类。例如我们需要从MQ获取实时数据,并根据从MQ获取到的JSON数据来处理不同的命令,那么这个调用者类应该为MQ所在的管理类(假如名为ActiveMQManager)。这时我们需要在ActiveMQManager类中维持对命令基类的引用,并在收到不同的JSON数据时解析出相应命令和命令参数信息,然后执行命令中的Action方法。
public abstract class Receiver {
public CommandArgs CommandArgs { get; set; }
protected const string LINE_BREAK =
"-------------------------" +
"-------------------------";
//文章排版需要,故折成2行
}
public class CreateReceiver : Receiver {
public void CreateInvoice() {
var args = CommandArgs as CreateArgs;
if (args == null) throw new InvalidOperationException();
Console.WriteLine("Create Invoice!");
Console.WriteLine(
$"InvoiceType is {args.InvoiceType},{Environment.NewLine}" +
$"BillingDate is {args.BillingDate.ToString("yyyy-MM-dd HH:mm:ss")}!");
Console.WriteLine(LINE_BREAK);
}
}
public class CancelReceiver : Receiver {
public void CancelInvoice() {
var args = CommandArgs as CancelArgs;
if (args == null) throw new InvalidOperationException();
Console.WriteLine("Cancel Invoice!");
Console.WriteLine(
$"InvoiceCode is {args.InvoiceCode},{Environment.NewLine}" +
$"InvoiceNumber is {args.InvoiceNumber},{Environment.NewLine}" +
$"InvoiceType is {args.InvoiceType},{Environment.NewLine}" +
$"CancelReason is {args.CancelReason},{Environment.NewLine}" +
$"CancelMan is {args.CancelMan},{Environment.NewLine}" +
$"CancelDate is {args.CancelDate.ToString("yyyy-MM-dd HH:mm:ss")}!");
Console.WriteLine(LINE_BREAK);
}
}
public class PrintReceiver : Receiver {
public void PrintInvoice() {
var args = CommandArgs as PrintArgs;
if (args == null) throw new InvalidOperationException();
Console.WriteLine("Print Invoice!");
Console.WriteLine(
$"InvoiceCode is {args.InvoiceCode},{Environment.NewLine}" +
$"InvoiceNumber is {args.InvoiceNumber},{Environment.NewLine}" +
$"InvoiceType is {args.InvoiceType}!");
Console.WriteLine(LINE_BREAK);
}
}
接收者基类Receiver和它的3个具体接收者类,需要维持对命令参数基类的引用,以便我们可以获取相应信息。接收者基类并不是命令模式必须的,但考虑到里氏替换原则和开闭原则,我们引入接收者基类并在不同的实现类里解耦不同的命令操作。
public class Program {
private static Receiver _receiver = null;
public static void Main(string[] args) {
_receiver = new CreateReceiver();
Command command = new CreateCommand(
_receiver, new CreateArgs {
InvoiceType = "004",
BillingDate = DateTime.UtcNow
});
var invoker = new Invoker(command);
invoker.Execute();
_receiver = new CancelReceiver();
command = new CancelCommand(
_receiver, new CancelArgs {
InvoiceCode = "310987289304",
InvoiceNumber = 34156934,
InvoiceType = "007",
CancelReason = "Invoice missing!",
CancelMan = "Iori",
CancelDate = DateTime.UtcNow
});
invoker = new Invoker(command);
invoker.Execute();
_receiver = new PrintReceiver();
command = new PrintCommand(
_receiver, new PrintArgs {
InvoiceCode = "310987289304",
InvoiceNumber = 34156934,
InvoiceType = "026"
});
invoker = new Invoker(command);
invoker.Execute();
Console.ReadKey();
}
}
以上是为了测试本案例所编写的代码,通过不同的命令并提供额外的参数化命令信息来执行不同的功能。以下是这个案例的输出结果:
Create Invoice!
InvoiceType is 004,
BillingDate is 2018-07-19 05:34:45!
--------------------------------------------------
Cancel Invoice!
InvoiceCode is 310987289304,
InvoiceNumber is 34156934,
InvoiceType is 007,
CancelReason is Invoice missing!,
CancelMan is Iori,
CancelDate is 2018-07-19 05:34:45!
--------------------------------------------------
Print Invoice!
InvoiceCode is 310987289304,
InvoiceNumber is 34156934,
InvoiceType is 026!
--------------------------------------------------
命令模式(Command Pattern)是一种行为型设计模式,它具有多种优点,可以帮助构建更灵活、可扩展和可维护的软件系统。以下是命令模式的一些主要优点:
命令模式是一种非常有用的设计模式,它提供了一种松耦合的方式来处理请求和操作,并支持一系列附加功能,如撤销、重做、批处理和队列。通过将命令封装成对象,可以增强系统的可维护性、可扩展性和可重用性,使得它在各种应用场景中都具有广泛的适用性。
虽然命令模式(Command Pattern)具有许多优点,但也存在一些缺点,需要在使用时考虑。以下是一些常见的命令模式的缺点:
虽然命令模式在许多情况下是有用的,但它也不是一种适用于所有情况的解决方案。在使用命令模式时,需要权衡其优点和缺点,并根据具体的需求和情境来决定是否使用该模式。如果命令模式能够提供所需的灵活性和可维护性,那么它通常是一个有价值的选择。
命令模式(Command Pattern)适用于许多场景,特别是在需要解耦请求发送者和请求接收者,支持撤销和重做操作,以及实现队列、批处理和日志记录等功能时,它特别有用。以下是一些适合使用命令模式的常见场景:
命令模式在需要将请求封装成独立对象、支持撤销和重做、实现队列和批处理等情况下非常有用。它有助于提高系统的灵活性、可维护性和可扩展性,使代码更加模块化和清晰。因此,在这些场景中考虑使用命令模式