【HeadFirst系列之HeadFirst设计模式】第7天之命令模式:封装请求,轻松实现解耦!

命令模式:封装请求,轻松实现解耦!

大家好!今天我们来聊聊设计模式中的命令模式(Command Pattern)。如果你曾经需要将请求封装成对象,或者希望实现请求的撤销、重做等功能,那么命令模式就是你的不二之选!本文基于《Head First 设计模式》的命令模式章节,通过生动的故事和 Java 代码示例,带你轻松掌握命令模式的精髓。

在这里插入图片描述


1. 命令模式是什么?

命令模式是一种行为型设计模式,它将请求封装成对象,从而使你可以用不同的请求对客户进行参数化,并支持请求的排队、记录日志、撤销等操作。命令模式的核心思想是解耦请求的发送者和接收者,使得系统更加灵活和可扩展。

适用场景

  • 需要将请求封装成对象,以便在不同的上下文中使用。
  • 需要支持请求的撤销、重做、排队等功能。
  • 需要解耦请求的发送者和接收者。

2. 命令模式的实现

故事背景

小明开发了一个智能家居系统,系统中有一个遥控器(RemoteControl)类,用于控制各种家电设备,比如(Light)、风扇(Fan)等。每个设备都有不同的操作,比如打开、关闭、调节亮度等。

问题出现

如果直接在遥控器中调用设备的方法,会导致遥控器和设备之间的耦合度过高。此外,如果需要支持撤销操作,代码会变得非常复杂。

解决方案:命令模式

小明决定使用命令模式,将每个操作封装成一个命令对象,从而解耦遥控器和设备。

代码实现

1. 定义命令接口
// 命令接口
interface Command {void execute();void undo();
}
2. 实现具体命令
// 具体命令:打开灯
class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.on();}@Overridepublic void undo() {light.off();}
}// 具体命令:关闭灯
class LightOffCommand implements Command {private Light light;public LightOffCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.off();}@Overridepublic void undo() {light.on();}
}// 具体命令:打开风扇
class FanOnCommand implements Command {private Fan fan;public FanOnCommand(Fan fan) {this.fan = fan;}@Overridepublic void execute() {fan.on();}@Overridepublic void undo() {fan.off();}
}// 具体命令:关闭风扇
class FanOffCommand implements Command {private Fan fan;public FanOffCommand(Fan fan) {this.fan = fan;}@Overridepublic void execute() {fan.off();}@Overridepublic void undo() {fan.on();}
}
3. 定义设备类
// 灯类
class Light {public void on() {System.out.println("Light is on");}public void off() {System.out.println("Light is off");}
}// 风扇类
class Fan {public void on() {System.out.println("Fan is on");}public void off() {System.out.println("Fan is off");}
}
4. 实现遥控器
// 遥控器类
class RemoteControl {private Command[] onCommands;private Command[] offCommands;private Command undoCommand;public RemoteControl() {onCommands = new Command[2];offCommands = new Command[2];Command noCommand = new NoCommand();for (int i = 0; i < 2; i++) {onCommands[i] = noCommand;offCommands[i] = noCommand;}undoCommand = noCommand;}public void setCommand(int slot, Command onCommand, Command offCommand) {onCommands[slot] = onCommand;offCommands[slot] = offCommand;}public void onButtonWasPushed(int slot) {onCommands[slot].execute();undoCommand = onCommands[slot];}public void offButtonWasPushed(int slot) {offCommands[slot].execute();undoCommand = offCommands[slot];}public void undoButtonWasPushed() {undoCommand.undo();}
}// 空命令类
class NoCommand implements Command {@Overridepublic void execute() {System.out.println("No command assigned");}@Overridepublic void undo() {System.out.println("No command assigned");}
}
5. 客户端代码
public class SmartHomeApp {public static void main(String[] args) {// 创建设备Light livingRoomLight = new Light();Fan livingRoomFan = new Fan();// 创建命令Command lightOn = new LightOnCommand(livingRoomLight);Command lightOff = new LightOffCommand(livingRoomLight);Command fanOn = new FanOnCommand(livingRoomFan);Command fanOff = new FanOffCommand(livingRoomFan);// 创建遥控器RemoteControl remoteControl = new RemoteControl();remoteControl.setCommand(0, lightOn, lightOff);remoteControl.setCommand(1, fanOn, fanOff);// 操作遥控器remoteControl.onButtonWasPushed(0); // 输出: Light is onremoteControl.offButtonWasPushed(0); // 输出: Light is offremoteControl.undoButtonWasPushed(); // 输出: Light is onremoteControl.onButtonWasPushed(1); // 输出: Fan is onremoteControl.offButtonWasPushed(1); // 输出: Fan is offremoteControl.undoButtonWasPushed(); // 输出: Fan is on}
}

3. 命令模式的优点

  1. 解耦请求的发送者和接收者
    命令模式将请求封装成对象,使得请求的发送者和接收者之间没有直接的依赖关系。

  2. 支持撤销和重做
    通过实现 undo() 方法,可以轻松实现撤销操作。

  3. 支持请求的排队和日志记录
    命令对象可以被存储、传递和记录,从而支持请求的排队和日志记录。

  4. 易于扩展
    新增命令时,只需实现新的命令类,无需修改现有代码。


4. 总结

命令模式通过将请求封装成对象,实现了请求的发送者和接收者之间的解耦,从而使得系统更加灵活和可扩展。通过本文的讲解和代码示例,相信你已经掌握了命令模式的核心思想和实现方法。在实际开发中,命令模式非常适合用于实现撤销、重做、排队等功能。


互动话题
你在项目中用过命令模式吗?遇到过哪些问题?欢迎在评论区分享你的经验!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/22742.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

敏捷开发07:敏捷项目可视化管理-ScrumBoard(Scrum板)使用介绍

ScrumBoard(Scrum板)介绍 ScrumBoard&#xff08;Scrum板&#xff09;是敏捷项目管理中使用的可视化工具&#xff0c;用于跟踪和监控冲刺阶段的任务进度。 主要通过可视化的看板来管理工作&#xff0c;它可视化了敏捷开发中的工作流程、任务状态、团队角色。 Scrum 团队在各…

Linux第十三节 — 进程状态详解

只要一个进程的PCB还存在内存当中&#xff0c;哪怕此时该进程对应的代码和数据已经在磁盘当中&#xff0c;此时依然认为该进程仍然存在&#xff01; 一、Linux进程的运行状态R 接下来我们看下面这个例子&#xff1a; 当我们执行这个程序的时候&#xff0c;我们认为该进程的状…

无人机遥控器接口作用详解!

USB接口&#xff1a; 功能&#xff1a;USB接口是一种通用串行总线接口&#xff0c;用于连接外部设备&#xff0c;如手机、平板、电脑或充电设备。在无人机遥控器上&#xff0c;USB接口通常用于数据传输和充电。 应用&#xff1a;用户可以通过USB接口将遥控器与电脑连接&#…

SVN把英文换中文

原文链接&#xff1a;SVN设置成中文版本 都是英文&#xff0c;换中文 Tortoise SVN 安装汉化教程(乌龟SVN) https://pan.quark.cn/s/cb6f2eee3f90 下载中文包

云手机如何进行经纬度修改

云手机如何进行经纬度修改 云手机修改经纬度的方法因不同服务商和操作方式有所差异&#xff0c;以下是综合多个来源的常用方法及注意事项&#xff1a; 通过ADB命令注入GPS数据&#xff08;适用于技术用户&#xff09; 1.连接云手机 使用ADB工具连接云手机服务器&#xff0c;…

【微服务优化】ELK日志聚合与查询性能提升实战指南

网罗开发 &#xff08;小红书、快手、视频号同名&#xff09; 大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等…

transfmer学习认识

整体架构 1.自注意机制 1.1.softmax 在机器学习和深度学习中&#xff0c;softmax 函数是一个常用的激活函数&#xff0c;用于将一个向量转换为一个概率分布。softmax 函数的公式如下&#xff1a; ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/35c158988402498ba6…

在 macOS 的 ARM 架构上按住 Command (⌘) + Shift + .(点)。这将暂时显示隐藏文件和文件夹。

在 macOS 的 ARM 架构&#xff08;如 M1/M2 系列的 Mac&#xff09;上&#xff0c;设置 Finder&#xff08;访达&#xff09;来显示隐藏文件夹的步骤如下&#xff1a; 使用快捷键临时显示隐藏文件&#xff1a; 在Finder中按住 Command (⌘) Shift .&#xff08;点&#xff…

【HarmonyOS NEXT星河版开发实战】天气查询APP

目录 前言 界面效果展示 首页 添加和删除 界面构建讲解 1. 获取所需数据 2. 在编译器中准备数据 3. index页面代码讲解 3.1 导入模块&#xff1a; 3.2 定义组件&#xff1a; 3.3 定义状态变量: 3.4 定义Tabs控制器: 3.5 定义按钮样式&#xff1a; 3.6 页面显示时触发…

idea debug功能演示线程安全问题

概述 用idea debug功能演示上一篇博客中提到的 本实现中的出队、入队的实现逻辑会不会有线程安全问题&#xff1f;如果有&#xff0c;怎么解决&#xff1f; 测试用例 package com.lovehena.datastructure.test;import com.lovehena.datastructure.ArrayQueue;/* * 测试 offer…

力扣每日一题【算法学习day.132】

前言 ###我做这类文章一个重要的目的还是记录自己的学习过程&#xff0c;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非常非常高滴&#xff01;&#xff01;&#xff01; 习题 1.统计相似字符串对的数目 题目链…

C++操作符重载案例

在学习ZLToolKit源码时&#xff0c;发现代码中涉及好多运算符重载&#xff0c;因此对其做一下归类学习。 直接写一个代码案例如下&#xff1a; #include <iostream> #include <memory> #include <functional>// 定义类 A class A { public:A(int a) { _a a…

Kafka系列之:记录一次源头数据库刷数据,造成数据丢失的原因

Kafka系列之:记录一次源头数据库刷数据,造成数据丢失的原因 一、背景二、查看topic日志信息三、结论四、解决方法一、背景 源头数据库在很短的时间内刷了大量的数据,部分数据在hdfs丢失了 理论上debezium数据采集不会丢失,就需要排查数据链路某个节点是否有数据丢失。 数据…

爬虫小案例豆瓣电影top250(json格式)

1.json格式&#xff08;仅供学习参考&#xff09; import requests, json, jsonpathclass Start(object):# 类实例化时会执行def __init__(self):self.headers {user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.…

位运算实用技巧与LeetCode实战

位操作&#xff08;Bit Manipulation&#xff09;有很多有趣的技巧&#xff0c;其中一个比较著名的资源是 Bit Twiddling Hacks 网站&#xff0c;它收集了各种位操作的高阶玩法&#xff0c;网址是&#xff1a; http://graphics.stanford.edu/~seander/bithacks.html 不过&…

Android输入事件传递流程系统源码级解析

1. 硬件层到Linux内核 设备节点&#xff1a;触摸事件由内核驱动捕获&#xff0c;写入/dev/input/eventX。关键结构体&#xff1a;input_event&#xff08;包含时间戳、类型、代码、值&#xff09;。 2. Native层处理&#xff08;system_server进程&#xff09; 2.1 EventHub …

【云安全】云原生-Docker(六)Docker API 未授权访问

Docker API 未授权访问 是一个非常严重的安全漏洞&#xff0c;可能导致严重的安全风险。 什么是 Docker API &#xff1f; Docker API 是 Docker 容器平台提供的一组 RESTful API&#xff0c;用于与 Docker 守护程序进行通信和管理 Docker 容器。通过 Docker API&#xff0c;…

请说明C#中的List是如何扩容的?

在 C# 中&#xff0c;List<T>是一个动态数组&#xff0c;它会根据需要自动调整其容量以容纳更多的元素。 目录 1 扩容条件与扩容算法规则 2 总结 1 扩容条件与扩容算法规则 当你创建一个新的List<T>实例时&#xff0c;如果没有指定初始容量&#xff0c;它会使…

Screen Wonders for Mac v3.3.1 3D屏保应用 支持M、Intel芯片

应用介绍 Screen Wonders 是一款专为 macOS 设计的屏保应用&#xff0c;它提供了多种高质量的动态屏保选择&#xff0c;旨在为用户的屏幕增添美感和个性化元素。 如果你厌倦了桌面上静止的图片&#xff0c;如果你准备好迎接世界各地甚至平行宇宙的魔力&#xff0c;我们在这个…

Apache Struts RCE (CVE-2024-53677)

前言 对目前的Apache Struts RCE (CVE-2024-53677)的poc进行总结&#xff0c;由于只能单个ip验证&#xff0c;所以自己更改一下代码&#xff0c;实现&#xff1a;多线程读取url验证并保存&#xff0c;更改为中文解释 免责声明 请勿利用文章内的相关技术从事非法测试&#xf…