如何在 Java 中实现命令设计模式
大家好,今天,我们将学习一种重要的设计模式,它经常被 Java 开发人员忽视。 是的,我说的是命令模式,它可以帮助我们编写灵活、松散耦合的代码来实现应用程序中的操作和事件。 简而言之,命令设计模式用于将动作请求与实际执行动作的对象分开。 Invoker 和 Receiver 对象之间的这种解耦提供了一种执行不同类型操作的统一方式。 这种解耦是使用 Command 对象实现的,它通常是一个带有 execute()
等方法的接口。
Requestor 或 Invoker 只知道 Command 对象,并不关心处理请求的实际对象,这可能是不同的。 这种透明性导致调用者端的代码更清晰,也使有机会在命令端做一些聪明的事情。
我们的 Command 对象可以像简单地将请求委托给 Receiver 一样愚蠢,也可以像记录执行 UNDO 和 REDO 功能的最后命令一样聪明。
命令模式确保我们的代码符合开放封闭设计原则,即 SOLID
设计原则的 O,这意味着添加新命令将非常容易,创建 Command
接口的新实现并且不会影响 Invoker 代码。
命令模式在 GUI 应用程序中特别流行,我们在其中使用许多命令,如打开、关闭、保存、剪切、复制、粘贴以及相应的 UNDO 和 REDO 操作。
1. 命令模式术语
在进一步使用 Java 实现命令模式之前,让我们先熟悉一下该模式中使用的术语。
- Client - 创建具体命令对象并使用 Receiver 配置
- Invoker - 谁持有命令并调用 Command 对象上的 execute() 方法
- Receiver - 处理请求的实际对象
- Command - 接口,它接受调用者的请求并委托给接收者
- ConcreteCommand - 执行特定任务的 Command 接口的实现
命令设计模式的 UML 图
这是命令设计模式的 UML 图,这将使事情更清楚。
我们可以看到 Client 有一个 CallbackInterface
的引用,它有一个通用方法 execute()
。 各个命令实现了这个接口并提供了一个实现,它只不过是委托给实际的对象来做事。
重要的是客户端不知道代表这些命令执行操作的 Actual 对象。 这种解耦产生了灵活的代码,并且可以轻松添加新命令而不影响客户端代码。
这是可能的,因为开闭设计原则使代码对扩展开放但对修改关闭。
2. Java 中的命令设计模式 - 示例
下面是我们的示例程序,用于演示如何在 Java 中使用命令模式。
此类代表命令模式的客户端
Client.java
import java.util.HashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Client { private static final Logger logger = LoggerFactory.getLogger(Client.class); public static void main(String args[]) { // Client creates Invoker object, command object and configure them Menu menu = new Menu(); menu.setCommand("Create", new CreateCommand()); menu.setCommand("Delete", new DeleteCommand()); //Invoker invokes command menu.runCommand("Create"); menu.runCommand("Delete"); } }
这个类代表一个命令
Menu.java
public class Menu{ Map menuItems = new HashMap(); public void setCommand(String operation, Command cmd){ menuItems.put(operation, cmd); } public void runCommand(String operation){ menuItems.get(operation).execute(); } }
表示命令的接口:
Command.java
interface Command { public void execute(); }
命令接口的一些实现,这个命令会删除文件
DeleteCommand.java
public class DeleteCommand implements Command { @Override public void execute() { System.out.println("Deleting file"); } }
创建文件的命令接口的另一种实现:
CreateCommand.java
public class CreateCommand implements Command { @Override public void execute() { System.out.println("Creating file"); } }
我们可以看到我们使用命令模式创建了两个命令 Create
和 Delete
。 它也是 GOF 模式之一。
我们可以看到 Command 是一个接口,CreateCommand
和 DeleteCommand
都实现了该接口并实现了 execute()
方法来放置命令应该执行的逻辑。
3. Java 命令模式的真实示例
学习和理解设计模式的最好方法之一是探索尽可能多的现实生活中的例子。 看看像 Spring、项目或库这样的特定框架如何使用一种模式来帮助开发识别用例所需的洞察力,在这些用例中可以应用模式。
每当我学习一种新的设计模式时,我总是会在核心 Java 库中查找它的使用情况。 由于每个 Java 程序员每天都使用 JDK 库,因此连接到示例的机会比任何随机的琐碎示例都多。
JDK 的两个命令模式示例是 java.lang.Runnable
和 javax.swing.Action
接口。 如果仔细观察,我们会发现线程池执行程序是 Runnable 命令的调用程序。
4.命令设计模式的好处
正如我们在本文中看到的,在 Java 中使用命令模式的主要好处是将命令的调用者与执行实际处理的对象分离。 通过解耦它们并使用引入 Command 对象,我们创建了一个设计,可以跟踪通过 Command 对象更改的每个状态。
这些知识可以用于有用的目的,例如 实现 UNDO 和 REDO 操作,请求的记录或排队等。简而言之,命令设计模式提供了以下优点:
-
封装请求处理。
-
将客户端与实际处理请求的对象分离,并提供统一的方式来执行类似的任务。
-
由于命令模式封装了请求,它可用于记录状态、实现撤消和重做功能、对请求进行排队等。
-
命令模式使得添加新命令变得容易。 它还遵循 Open Closed 设计原则,即通过创建新代码来添加新功能。 由于请求处理对 Invoker 是透明的,因此添加新命令不需要在他们这边进行更改。
5.命令模式的缺点
与任何其他设计决策一样,命令模式也涉及权衡。 如果我们有很多命令,就像在 Eclipse 或 IntelliJIDEA 等流行的 Java IDE 等主要 GUI 应用程序中一样,我们最终可能会得到很多小的命令类。
虽然类似的功能可以分为几个类,每个方法针对特定命令执行一个任务。
顺便说一下,使用命令模式会产生可读、可维护和可扩展的代码,所以这个成本是值得付出的。
这就是关于 Java 中的命令模式和面向对象编程的全部内容。 使用命令模式来封装请求处理并将方法的调用与实际处理该请求的对象分开。
命令设计模式也可以用于做一些聪明的事情,而不是仅仅将请求委托给接收者,比如。 我们可以记录和排队处理请求,可以执行撤消操作,并可以执行预处理操作,例如 用于审计等的日志记录请求
相关文章
使用 Java 在 MongoDB 中生成 ObjectId
发布时间:2023/04/20 浏览次数:179 分类:MongoDB
-
本文将讨论 ObjectId 以及我们如何使用 Java 程序生成它。 为了使主题更简单,我们将看到一个带有解释的示例,以使主题更容易。
在 PHP 变量中存储 Div Id 并将其传递给 JavaScript
发布时间:2023/03/29 浏览次数:69 分类:PHP
-
本文教导将 div id 存储在 PHP 变量中并将其传递给 JavaScript 代码。
如何在 Java 中把日期转换为字符串
发布时间:2023/03/28 浏览次数:192 分类:Java
-
本篇文章介绍了如何在 Java 中把 java.util.Date 转换为字符串 String。