设计模式-命令模式在Java中的使用示例-桌面程序自定义功能键

场景

欲开发一个桌面版应用程序,该应用程序为用户提供了一系列自定义功能键,用户可以通过这些功能键来实现一些快捷操作。

用户可以将功能键和相应功能绑定在一起,还可以根据需要来修改功能键的设置,而且系统在未来可能还会增加一些新的功能或功能键。

如果不使用命令模式,可能这样实现。

功能键类FunctionButton充当请求的发送者,帮助文档处理类HelpHandler充当请求的接收者,在发送者FunctionButton的onClick()

方法中将调用接收者HelpHandler的display()方法。

FunctionButton:

public class FunctionButton {
    //帮助文档处理类,请求接收者
    private HelpHandler helperHandler;

    public void onClick(){
        helperHandler = new HelpHandler();
        //显示帮助文档
        helperHandler.display();
    }
}

HelpHandler:

public class HelpHandler {
    public void display(){
        System.out.println("显示帮助文档");
    }
}

以上存在的问题:

(1) 由于请求发送者和请求接收者之间存在方法的直接调用,耦合度很高,更换请求接收者必须修改发送者的源代码,

如果需要将请求接收者HelpHandler改为WindowHanlder(窗口处理类),则需要修改FunctionButton的源代码,违背了“开闭原则”。

(2) FunctionButton类在设计和实现时功能已被固定,如果增加一个新的请求接收者,如果不修改原有的FunctionButton类,

则必须增加一个新的与FunctionButton功能类似的类,这将导致系统中类的个数急剧增加。

由于请求接收者HelpHandler、WindowHanlder等类之间可能不存在任何关系,它们没有共同的抽象层,

因此也很难依据“依赖倒转原则”来设计FunctionButton。

(3) 用户无法按照自己的需要来设置某个功能键的功能,一个功能键类的功能一旦固定,在不修改源代码的情况下无法更换其功能,

系统缺乏灵活性。

命令模式概述

在软件开发中,我们经常需要向某些对象发送请求(调用其中的某个或某些方法),但是并不知道请求的接收者是谁,

也不知道被请求的操作是哪个,此时,我们特别希望能够以一种松耦合的方式来设计软件,使得请求发送者与请求接收者

能够消除彼此之间的耦合,让对象之间的调用关系更加灵活,可以灵活地指定请求接收者以及被请求的操作。

命令模式为此类问题提供了一个较为完美的解决方案。

命令模式可以将请求发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,

而不必知道如何完成请求。

命令模式(Command Pattern):

将一个请求封装为一个对象,从而让我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。

命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。

命令模式结构图

命令模式包含的各角色:

Command(抽象命令类):

抽象命令类一般是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法,

通过这些方法可以调用请求接收者的相关操作。

ConcreteCommand(具体命令类):

具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接收者对象,

将接收者对象的动作绑定其中。在实现execute()方法时,将调用接收者对象的相关操作(Action)。

Invoker(调用者):

调用者即请求发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接收者,

因此它只与抽象命令类之间存在关联关系。在程序运行时可以将一个具体命令对象注入其中,

再调用具体命令对象的execute()方法,从而实现间接调用请求接收者的相关操作。

Receiver(接收者):

接收者执行与请求相关的操作,它具体实现对请求的业务处理。命令模式的本质是对请求进行封装,

一个请求对应于一个命令,将发出命令的责任和执行命令的责任分割开。每一个命令都是一个操作:

请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行相应的操作。

命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,

更不必知道请求如何被接收、操作是否被执行、何时被执行,以及是怎么被执行的。

注:

博客:
霸道流氓气质_C#,架构之路,SpringBoot-CSDN博客

实现

使用命令模式实现以上用户自定义功能键。

1、新建抽象命令类

//抽象命令类
abstract class Command {
    public abstract void execute();
}

2、新建具体命令类:帮助命令类

//帮助命令类:具体命令类
public class HelpCommand extends Command{

    //维持对请求接收者的引用
    private HelpHandler helpHandler;

    public HelpCommand(){
        helpHandler = new HelpHandler();
    }

    //命令执行方法,将调用请求接收者的业务方法
    public void execute() {
        helpHandler.display();
    }
}

其中维持着对请求接收者的引用。

3、新建请求接收者,帮助文档的处理类

//帮助文档处理类:请求接受者
public class HelpHandler {
    public void display(){
        System.out.println("显示帮助文档");
    }
}

4、同理新建具体命令类:最小化命令类

//最小化命令类:具体命令类
public class MinimizeCommand extends Command{

    //维持对请求接收者的引用
    private WindowHandler windowHandler;

    public MinimizeCommand(){
        windowHandler = new WindowHandler();
    }

    //命令执行方法,将调用请求接收者的业务方法
    public void execute() {
        windowHandler.minimize();
    }
}

其中维持着对请求接收者最小化窗口处理类的引用

5、新建最小化窗口处理类

//窗口处理类:请求接收者
public class WindowHandler {
    public void minimize(){
        System.out.println("将窗口最小化");
    }
}

6、新建请求发送者:功能键类

//功能键类:请求发送者
public class FunctionButton {
    //功能键名称
    private String name;
    //维持一个抽象命令对象的引用
    private Command command;

    public FunctionButton(String name) {
        this.name = name;
    }

    public String getName(){
        return this.name;
    }

    //为功能键注入命令
    public void setCommand(Command command){
        this.command = command;
    }

    public void onClick(){
        System.out.println("点击功能键:");
        command.execute();
    }
}

7、新建功能键设置窗口类

import java.util.ArrayList;

//功能键设置窗口类
public class FBSettingWindow {
    //窗口标题
    private String title;
    //定义一个ArrayList来存储所有功能键
    private ArrayList<FunctionButton> functionButtons = new ArrayList<FunctionButton>();

    public FBSettingWindow(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public void addFunctionButton(FunctionButton fb){
        functionButtons.add(fb);
    }

    public void removeFunctionButton(FunctionButton fb){
        functionButtons.remove(fb);
    }

    //显示窗口及功能键
    public void display(){
        System.out.println("显示窗口:"+this.title);
        System.out.println("显示功能键:");
        for (Object obj : functionButtons) {
            System.out.println(((FunctionButton)obj).getName());
        }
        System.out.println("-------------------------");
    }
}

8、客户端调用方式

public class Client {
    public static void main(String[] args) {
        FBSettingWindow fbsw = new FBSettingWindow("功能键设置");

        FunctionButton fb1,fb2;
        fb1 = new FunctionButton("功能键1");
        fb2 = new FunctionButton("功能键2");

        Command command1,command2;
        //通过读取配置文件或其它方式生成具体命令对象
        command1 = new HelpCommand();
        command2 = new MinimizeCommand();

        //将命令对象注入功能键
        fb1.setCommand(command1);
        fb2.setCommand(command2);

        fbsw.addFunctionButton(fb1);
        fbsw.addFunctionButton(fb2);
        fbsw.display();

        //调用功能键的业务方法
        fb1.onClick();
        fb2.onClick();

    }
}

9、总结

如果需要修改功能键的功能,例如某个功能键可以实现“自动截屏”,只需要对应增加一个新的具体命令类,

在该命令类与屏幕处理者(ScreenHandler)之间创建一个关联关系,然后将该具体命令类的对象通过配置文件注入到某个功能键即可,

原有代码无须修改,符合“开闭原则”。在此过程中,每一个具体命令类对应一个请求的处理者(接收者),

通过向请求发送者注入不同的具体命令对象可以使得相同的发送者对应不同的接收者,从而实现“将一个请求封装为一个对象,

用不同的请求对客户进行参数化”,客户端只需要将具体命令对象作为参数注入请求发送者,无须直接操作请求的接收者。

命令模式的主要优点:

(1) 降低系统的耦合度。由于请求者与接收者之间不存在直接引用,因此请求者与接收者之间实现完全解耦,

相同的请求者可以对应不同的接收者,同样,相同的接收者也可以供不同的请求者使用,两者之间具有良好的独立性。

(2) 新的命令可以很容易地加入到系统中。由于增加新的具体命令类不会影响到其他类,因此增加新的具体命令类很容易,

无须修改原有系统源代码,甚至客户类代码,满足“开闭原则”的要求。

(3) 可以比较容易地设计一个命令队列或宏命令(组合命令)。

(4) 为请求的撤销(Undo)和恢复(Redo)操作提供了一种设计和实现方案。

命令模式的主要缺点如下:

使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个对请求接收者的调用操作都需要设计一个具体命令类,

因此在某些系统中可能需要提供大量的具体命令类,这将影响命令模式的使用。

适用场景

在以下情况下可以考虑使用命令模式:

(1) 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。请求调用者无须知道接收者的存在,也无须知道接收者是谁,

接收者也无须关心何时被调用。

(2) 系统需要在不同的时间指定请求、将请求排队和执行请求。一个命令对象和请求的初始调用者可以有不同的生命期,

换言之,最初的请求发出者可能已经不在了,而命令对象本身仍然是活动的,可以通过该命令对象去调用请求接收者,

而无须关心请求调用者的存在性,可以通过请求日志文件等机制来具体实现。

(3) 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。

(4) 系统需要将一组操作组合在一起形成宏命令。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

P5691 [NOI2001] 方程的解数

题目 思路 暴搜显然会TLE&#xff0c;所以这时候就应该请出DFS的伙伴——折半搜索&#xff08;meet in the middle&#xff09;了 折半搜索的思路就是先搜完后一半后&#xff0c;借助这一半的数据来搜索前一半&#xff0c;效率是原来的2倍 这个题怎么才能折半搜索呢&#xff1…

【Linux】更换jdk版本

目录 一、前言二、查看jdk版本号1、项目中的版本号&#xff08;pom.xml&#xff09;2、服务器中的版本号 三、更换jdk版本1、创建java文件夹2、下载并解压JDK安装包①、下载jdk安装包②、移动到创建好的/usr/local/java路径下③、解压jdk安装包 四、删除原来的jdk版本1、删除原…

Qt: 查看qmake相关参数设置

Qt开发中&#xff0c;经常会遇到qmake相关问题&#xff0c;比如同时安装了多个Qt版本的情况。比如我的情况是系统自带了Qt 5.12.8, 但是开发中遇到一些兼容性问题&#xff0c;于是又手动安装了5.9.8。 查看qmake版本&#xff0c;qmake -v, 虽然项目中已经指定了5.9.8, 但是系统…

【力扣每日一题】2023.7.30 环形链表2

题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 这道题属于是那种知道解法就很简单&#xff0c;不知道解法就很难独立想出来的那种&#xff0c;我们只需要稍微记住这类题的固定解法就可以。 所以接下来我先说解法&#xff0c;再解释为什么解法可以解出来。 那么我们都…

数值线性代数: 共轭梯度法

本文总结线性方程组求解的相关算法&#xff0c;特别是共轭梯度法的原理及流程。 零、预修 0.1 LU分解 设&#xff0c;若对于&#xff0c;均有&#xff0c;则存在下三角矩阵和上三角矩阵&#xff0c;使得。 设&#xff0c;若对于&#xff0c;均有&#xff0c;则存在唯一的下三…

MyBatis(二)

文章目录 一.MyBatis的模式开发1.1 定义数据表和实体类1.2 配置数据源和MyBatis1.3 编写Mapper接口和增加xxxMapper.xml1.4 测试我们功能的是否实现. 二. Mybatis的增删查改操作2.1 单表查询2.2 多表查询三.动态SQL的实现3.1 什么是动态SQL3.2 动态SQL的使用if标签的使用trim标…

LeetCode559. N 叉树的最大深度

559. N 叉树的最大深度 文章目录 [559. N 叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-n-ary-tree/)一、题目二、题解方法一&#xff1a;迭代方法二&#xff1a;递归 一、题目 给定一个 N 叉树&#xff0c;找到其最大深度。 最大深度是指从根节点到最远叶…

【机器学习】Multiple Variable Linear Regression

Multiple Variable Linear Regression 1、问题描述1.1 包含样例的X矩阵1.2 参数向量 w, b 2、多变量的模型预测2.1 逐元素进行预测2.2 向量点积进行预测 3、多变量线性回归模型计算损失4、多变量线性回归模型梯度下降4.1 计算梯度4.2梯度下降 首先&#xff0c;导入所需的库 im…

架构的分类

目录 一、 RUP41 架构 1.1 RUP41架构方法概述 1.2 RUP41架构总体 1.3 RUP41架构方法内容 1.3.1 逻辑视图 1.3.2 开发视图 1.3.3 物理视图 1.3.4 处理视图 1.3.5 场景视图 ​二、 TOGAF9 架构 2.1 TOGAF9 架构概述 2.2 TOGAF9 架构分类 2.2.1 业务架构 2.2.2 数据架…

蓝海卓越计费管理系统远程命令执行

活着&#xff0c;就要时刻准备承受磨难&#xff01; 漏洞描述 蓝海卓越计费管理系统存在命令调试页面&#xff0c;导致攻击者可以远程命令执行 漏洞复现 访问 debug.php页面 远程调试命令执行 /debug.php漏洞证明 文笔生疏&#xff0c;措辞浅薄&#xff0c;望各位大佬不吝…

linux -网络编程-多线程并发服务器

目录 1.三次握手和四次挥手 2 滑动窗口 3 函数封装思想 4 高并发服务器 学习目标&#xff1a; 掌握三次握手建立连接过程掌握四次握手关闭连接的过程掌握滑动窗口的概念掌握错误处理函数封装实现多进程并发服务器实现多线程并发服务器 1.三次握手和四次挥手 思考: 为什么…

手把手教你使用stable diffusion生成自己的艺术二维码

艺术二维码制作指南 导读midjourneystable diffusion 环境准备安装stable diffusion webuisd-webui-qrcode-toolkit安装 草料二维码模型准备QR PatternQR Code MonsterIoC Lab Control Net 艺术二维码制作1. 二维码信息提取2. 使用QR Tookit生成二维码3. 下载二维码图片4. prom…

Modbus tcp转ETHERCAT网关modbus tcp/ip协议

捷米JM-ECT-TCP网关能够连接到Modbus tcp总线和ETHERCAT总线中&#xff0c;实现两种不同协议设备之间的通讯。这个网关能够大大提高工业生产的效率和生产效益&#xff0c;让生产变得更加智能化。捷米JM-ECT-TCP 是自主研发的一款 ETHERCAT 从站功能的通讯网关。该产品主要功能是…

一个监控系统的典型架构

监控系统的典型架构图&#xff0c;从左往右看&#xff0c;采集器是负责采集监控数据的&#xff0c;采集到数据之后传输给服务端&#xff0c;通常是直接写入时序库。然后就是对时序库的数据进行分析和可视化&#xff0c;分析部分最典型的就是告警规则判断&#xff0c;即图上的告…

【mysql学习篇】Order by与Group by优化以及排序算法详解

一、Order by与Group by优化 Case1&#xff1a; 分析&#xff1a; 利用最左前缀法则&#xff1a;中间字段不能断&#xff0c;因此查询用到了name索引&#xff0c;从key_len74也能看出&#xff0c;age索引列用在排序过程中&#xff0c;因为Extra字段里没有using filesort 注意…

擎创技术流 | 深入浅出运维可观测工具(二):eBPF应用中常见问题

上期跟大家聊了下eBPF的发展历史还有特性&#xff0c;点击这里↓↓↓擎创技术流 | 深入浅出运维可观测工具&#xff08;一&#xff09;&#xff1a;聊聊eBPF的前世今生&#xff0c;一键回看上期精彩内容。 这期主要跟大家分享下eBPF在应用过程中可能出现的问题&#xff0c;希望…

本地仓库推送至远程仓库

1. 本地生成ssh密钥对 ssh-keygen -t rsa -C 邮箱2. 添加公钥到gitlab/github/gitee上 打开C:\Users\用户名\.ssh目录下生成的密钥文件id_rsa.pub&#xff0c;把内容复制到如下文本框中 删除Expiration date显示的日期&#xff0c;公钥有效期变成永久&#xff0c;之后点Add K…

vmware中windows操作系统虚拟机安装

1.win10中安装 1.1 虚拟机向导 文件-新建虚拟机 典型-下一步 稍后安装操作系统-下一步 window10 64x -下一步 修改虚拟机名称及位置-下一步 默认60g,至少大于40g-将虚拟磁盘拆分成多个文件夹-下一步 点击完成 1.2 编辑虚拟机设置 移除打印机 设置虚拟机&#xff0c;加入iso映…

联想北京公司研发管理部高级经理周燕龙受邀为第十二届中国PMO大会演讲嘉宾

联想&#xff08;北京&#xff09;有限公司研发管理部高级经理周燕龙先生受邀为由PMO评论主办的2023第十二届中国PMO大会演讲嘉宾&#xff0c;演讲议题&#xff1a;PMO如何助力研发。大会将于8月12-13日在北京举办&#xff0c;敬请关注&#xff01; 议题简要&#xff1a; PMO在…

js中的遍历方法比较:map、for...in、for...of、reduce和forEach的特点与适用场景

&#x1f60a;博主&#xff1a;小猫娃来啦 &#x1f60a;文章核心&#xff1a;JavaScript中的遍历方法比较&#xff1a;map、for…in、for…of和forEach的特点与适用场景 文章目录 map 方法概述用法返回值特点 for...in 循环概述用法注意事项 for...of 循环概述用法可迭代对象…