迭代器模式与命令模式详解(3)

简介: 迭代器模式与命令模式详解(3)

五、命令模式定义

命令模式(Command Pattern )是对命令的封装,每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行操作。命令模式解耦了请求方和接收方,请求方只需请求执行命令,不用关心命令是怎样被接收,怎样被操作以及是否被执行…等。

命令模式属于行为型模式。


原 文 : Encapsulate a request as an object, there by letting you parameterize clients with different requests, queue or log requests,and support undoable operations.

解释:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能


在软件系统中,行为请求者与行为实现者通常是一种紧耦合关系,因为这样的实现简单明了。

但紧耦合关系缺乏扩展性,在某些场合中,当需要为行为进行记录,撤销或重做等处理时,只

能修改源码。而命令模式通过为请求与实现间引入一个抽象命令接口,解耦了请求与实现,并

且中间件是抽象的,它可以有不同的子类实现,因此其具备扩展性。所以,命令模式的本质是

解耦命令请求与处理。


六、命令模式的应用场景

当系统的某项操作具备命令语义时,且命令实现不稳定(变化),那么可以通过命令模式解耦请求与实现,利用抽象命令接口使请求方代码架构稳定,封装接收方具体命令实现细节。接收方与抽象命令接口呈现弱耦合(内部方法无需一致),具备良好的扩展性。


命令模式适用于

以下应用场景:


1、现实语义中具备"命令"的操作(如命令菜单,shell命令…);


2、请求调用者和请求的接收者需要解耦,使得调用者和接收者不直接交互;


3、需要抽象出等待执行的行为,比如撤销(Undo)操作和恢复(Redo)等操作;


4、需要支持命令宏(即命令组合操作)。


image.png


从 UML类图中,我们可以看到,命令模式 主要包含四种角色:


接收者角色(Receiver):该类负责具体实施或执行一个请求;


命令角色(Command ):定义需要执行的所有命令行为;


具体命令角色(Concrete Command )该类内部维护一个接收者(Receiver ),在其execute()

方法中调用Receiver的相关方法;


请求者角色(Invoker):接收客户端的命令,并执行命令。


从命令模式的UML类图中,其实可以很清晰地看出:Command的出现就是作为Receiver 和 Invoker的中间件,解耦了彼此。而之所以引入Command中间件,我觉得是以下两方面原因 :


解耦请求与实现:即解耦了 Invoker和 Receiver , 因为在UML类图中,Invoker是一个具

体的实现,等待接收客户端传入命令(即 Invoker与客户端耦合),Invoker处于业务逻辑区域, 应当是一个稳定的结构。而 Receiver是属于业务功能模块 是经常变动的 如果没有Command z 则 Invoker紧耦合Receiver , 一个稳定的结构依赖了一个不稳定的结构,就会导致整个结构都不稳定了。这也就是Command引入的原因:不仅仅是解耦请求与实现,同时稳定( Invoker)

依赖稳 定 (Command ),结构还是稳定的。


扩展性增强:扩展性体现在两个方面:


1、 Receiver属于底层细节,可以通过更换不同的Receiver达到不同的细节实现;


2、 Command接口本身就是抽象的,本身就具备扩展性;而且由于命令对象本身就具备抽 象 ,如果结合装饰器模式,功能扩展简直如鱼得水。


注:在一个系统中,不同的命令对应不同的请求,也就是说无法把请求抽象化,因此命令模式中的Receiver是具体实 现;但是如果在某一个模块中,可以对Receiver进行抽象,其实这就变相使用到了桥接模式(Command类具备两个变 化的维度:Command和 Receiver), 这样子的扩展性会更加优秀。


举个生活中的例子,相信80后的小伙伴应该都经历过普及黑白电视机的那个年代。黑白电

视机要换台那简直不容易,需要人跑上前去用力掰动电视机上那个切换频道的旋钮,一 顿 〃啪

啪啪〃折腾下来才能完成一次换台。如今时代好了,我们只需躺沙发上按一下遥控器就完成了

换台。这就是用到了命令模式,将换台命令和换台处理进行了分离。


另外,就是餐厅的点菜单,一般是后厨先把所有的原材料组合配置好了,客户用餐前只需要 点菜即可,将需求和处理进行了解耦。


19.3.命令模式在业务场景中的应用

假如我们自己开发一个播放器,播放器有播放功能、有拖动进度条功能、停止播放功能、暂

停功能,我们自己去操作播放器的时候并不是直接调用播放器的方法,而是通过一个控制条去传达指令给播放器内核,那么具体传达什么指令,会被封装为一个一个的按钮。那么每个按钮

的就相当于是对一条命令的封装。用控制条实现了用户发送指令与播放器内核接收指令的解耦。


下面来看代码,首先创建播放器内核GPlayer类:


public class GPlayer {
    public void play(){
        System.out.println("正常播放");
    }
    public void speed(){
        System.out.println("拖动进度条");
    }
    public void stop(){
        System.out.println("停止播放");
    }
    public void pause(){
        System.out.println("暂停播放");
    }
}
目录
相关文章
|
存储 算法 索引
LZW(Lempel-Ziv-Welch)
LZW(Lempel-Ziv-Welch)压缩算法是一种无损数据压缩算法,主要用于压缩文本文件和图像文件。它是由 Abraham Lempel、Jacob Ziv 和 Welch 共同发明的,基于哈夫曼编码和算术编码的思想,通过建立一个字典表对数据进行压缩。
771 2
|
存储 文件存储 对象存储
块存储、文件存储和对象存储特点对比
块存储、文件存储和对象存储特点对比
1898 2
|
6月前
|
人工智能 监控 算法
AI 技能树怎么搭?90%的人第一步就走错了
AI热潮下,别只学工具!真正的竞争力在于构建“AI能力树”:认知层(问题拆解、目标定义)、工程思维(风险评估、方案权衡)、工具协作(高效提问、结果验证)。工具是杠杆,能力才是支点。
|
9月前
|
供应链 JavaScript 安全
B/S云门诊系统源码,java云诊所源码,基于Spring Boot、Vue.js构建
云端SaaS架构云门诊系统,基于Spring Boot+Vue开发,支持医保结算,集成预约挂号、诊疗、收费、库存、会员管理等功能,适用于各类基层医疗机构,可打包为C/S桌面应用,支持外接设备免安装配置。
362 10
|
存储 分布式计算 大数据
基于阿里云大数据平台的实时数据湖构建与数据分析实战
在大数据时代,数据湖作为集中存储和处理海量数据的架构,成为企业数据管理的核心。阿里云提供包括MaxCompute、DataWorks、E-MapReduce等在内的完整大数据平台,支持从数据采集、存储、处理到分析的全流程。本文通过电商平台案例,展示如何基于阿里云构建实时数据湖,实现数据价值挖掘。平台优势包括全托管服务、高扩展性、丰富的生态集成和强大的数据分析工具。
|
前端开发 JavaScript 算法
如何开发人事及OA管理系统的绩效管理板块?(附架构图+流程图+代码参考)
本文深入解析了人事及OA系统中绩效管理模块的设计与实现,涵盖总体架构、功能模块、业务流程、开发技巧、数据库设计、前后端实现及核心算法等。内容详实,配有架构图、流程图和代码示例,适合HR系统开发者与管理者参考,助力构建高效、可扩展的绩效管理体系。
|
网络协议 物联网 网络安全
|
人工智能 搜索推荐 测试技术
通义灵码 2.0 智能编码功能评测:Deepseek 加持下的 Python 开发体验
通义灵码 2.0 智能编码功能评测:Deepseek 加持下的 Python 开发体验
846 11
|
数据采集 自然语言处理 开发工具
fasttext实现文本分类
fasttext实现文本分类
969 0
|
机器学习/深度学习 数据采集 算法
特征工程与数据预处理全解析:基础技术和代码示例
在机器学习和数据科学的世界里,数据的质量是建模成功与否的关键所在。这就是特征工程和数据预处理发挥作用的地方。本文总结的这些关键步骤可以显著提高模型的性能,获得更准确的预测,我们将深入研究处理异常值、缺失值、编码、特征缩放和特征提取的各种技术。
663 0