🏆本文收录于《聊设计模式》专栏,专门攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎持续关注&&收藏&&订阅!
前言
在面向对象设计中,设计模式是重要的一环。设计模式可以帮助我们更好地理解和分析代码,同时也能够提高代码的可读性、可扩展性和可维护性。命令模式是常用的设计模式之一,它将请求封装成一个对象,从而可以用不同的请求来进行参数化和操作化。本文将介绍命令模式的相关概念及实现方法。
摘要
本文将从以下几个方面来介绍命令模式:
- 命令模式的概念及作用
- 命令模式的实现方法
- 命令模式的优点和缺点
- 命令模式的应用场景
- 命令模式的拓展
- 命令模式的示例实现
- 小结
命令模式
概念
命令模式是一种行为设计模式,它将请求封装成一个对象,从而允许使用不同的请求、队列或者日志来参数化其他对象。命令模式的核心在于将请求和实现分离开,从而可以使请求具有独立的生命周期和实现。
结构
命令模式包含以下几个角色:
- 命令(
Command
):定义了一个操作的接口,包括执行操作的方法和撤销操作的方法。 - 具体命令(
ConcreteCommand
):实现了命令接口,包含了具体的操作和接受者。 - 接受者(
Receiver
):执行命令所要进行的操作,知道如何实现具体的请求。 - 调用者(
Invoker
):负责调用命令对象执行请求,通常会持有命令对象的实例。 - 客户端(
Client
):创建具体的命令对象并设置其接收者,命令对象的生命周期由客户端管理。
如下是命令模式的UML类图:
命令模式的作用在于允许客户端通过命令对象来将请求封装成一个独立的对象,从而可以方便地进行调用、传递和管理。命令模式还可以实现多级撤销、宏命令、命令队列等功能,是一个非常实用的设计模式。
命令模式的扩展
在软件开发中,有时将命令模式与前面学的组合模式联合使用,这就构成了宏命令模式,也叫组合命令模式。宏命令包含了一组命令,它充当了具体命令与调用者的双重角色,执行它时将递归调用它所包含的所有命令,其具体结构如下图所示:
优缺点
优点:
命令模式具有以下几个优点:
- 降低系统的耦合度:命令模式将请求和实现分离开,从而可以降低系统的耦合度,使得系统更易于扩展和维护。
- 可扩展性:命令模式可以实现多级撤销、宏命令和命令队列等功能,从而可以方便地扩展系统的功能。
- 灵活性:命令模式可以动态地添加或删除命令,从而可以灵活地组织命令流。
缺点:
命令模式也存在一些缺点:
- 过多的具体命令类:如果系统中有许多具体命令类,那么命令模式将会导致系统变得复杂,不易于维护。
- 命令发起者和命令执行者的解耦:虽然命令模式降低了系统的耦合度,但也会导致命令发起者和命令执行者之间的解耦问题。
应用场景
命令模式是一种常见的设计模式,可以应用于各种场景中,例如:
- 图形界面应用程序中的快捷键:将快捷键封装成一组命令对象,并将这些命令对象注册到快捷键管理器中,从而可以方便地进行调用和管理。
- 服务器端应用程序中的请求处理:将请求封装成一组命令对象,并将这些命令对象注册到请求处理器中,从而可以方便地进行调用、传递和管理。
- 游戏中的角色控制:将角色控制命令封装成一组命令对象,并将这些命令对象注册到角色管理器中,从而可以方便地进行调用、传递和管理。
模式实现
以下是命令模式的一个简单实现:
定义命令接口
package com.example.javaDesignPattern.command;
/**
* @Author bug菌
* @Date 2023-09-19 22:04
*/
public interface Command {
void execute();
void undo();
}
具体命令
package com.example.javaDesignPattern.command;
/**
* @Author bug菌
* @Date 2023-09-19 22:04
*/
public class ConcreteCommand implements Command {
private Receiver receiver;
public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}
public void execute() {
receiver.action();
}
public void undo() {
receiver.undo();
}
}
接受者
package com.example.javaDesignPattern.command;
/**
* @Author bug菌
* @Date 2023-09-19 22:05
*/
public class Receiver {
public void action() {
System.out.println("执行命令");
}
public void undo() {
System.out.println("撤销命令");
}
}
调用者
package com.example.javaDesignPattern.command;
/**
* @Author bug菌
* @Date 2023-09-19 22:05
*/
public class Invoker {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void executeCommand() {
command.execute();
}
public void undoCommand() {
command.undo();
}
}
客户端
package com.example.javaDesignPattern.command;
/**
* @Author bug菌
* @Date 2023-09-19 22:05
*/
public class Client {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker();
invoker.setCommand(command);
invoker.executeCommand();
invoker.undoCommand();
}
}
执行结果如下:
以上代码演示了命令模式的一个简单实现,其中包含了命令、具体命令、接受者、调用者和客户端几个角色。具体实现中,客户端创建了一个具体命令对象并将其设置到调用者中,调用者负责调用命令对象执行相应操作,并可以执行撤销操作。
示例代码解析
这是一个使用命令模式的示例代码。
在这段代码中,我们有三个类:
Receiver
(接收者):它包含了实际执行操作的方法。
Command
(命令):它包含了一个执行操作的抽象方法。
ConcreteCommand
(具体命令):它继承了命令类,并将接收者的对象作为参数传递给它。它实现了抽象方法,并调用接收者的方法来执行操作。
还有一个 Invoker(调用者),它持有命令对象并调用其 execute
方法来发出请求。Invoker
还可以调用其 undo
方法来撤销最后执行的命令。
在 main 方法中,我们首先创建了一个接收者对象,并将其传递给一个具体的命令对象。接下来,我们创建了一个调用者对象,并将命令对象设置为其持有的命令。最后,我们依次调用了调用者对象的 executeCommand
和 undoCommand
方法来执行命令和撤销命令。
总之,这个示例代码展示了命令模式如何将请求封装成对象,并使其可以在不同的上下文中执行和撤销。
小结
本文介绍了命令模式的相关概念和实现方法,以及其优点和缺点。命令模式是一种常见的设计模式,可以应用于各种场景中,例如图形界面应用程序、服务器端应用程序和游戏中的角色控制等。在应用命令模式时,需要充分考虑系统的需求和设计,选择合适的命令对象和接收者,从而可以实现系统的功能和需求。
附录源码
如上涉及代码均已上传同步在GitHub,提供给同学们参考性学习。
☀️建议/推荐你
如果想系统性的全面学习设计模式,建议小伙伴们直接毫无顾忌的关注这个专栏《聊设计模式》,无论你是想提升自己的编程技术,还是渴望更好地理解代码背后的设计思想,本专栏都会为你提供实用的知识和启发,帮助你更好地解决日常开发中的挑战,将代码变得更加优雅、灵活和可维护!
📣关于我
我是bug菌,CSDN | 掘金 | infoQ | 51CTO 等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,华为云 | 阿里云| 腾讯云等社区优质创作者,全网粉丝合计15w+ ;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等海量资料。