命令模式

news2024/11/26 23:24:55

文章目录

    • 思考命令模式
      • 1.命令模式的本质
      • 2.何时选用命令模式
      • 3.优缺点
      • 4.实现
        • 耦合写法
        • 命令模式写法
        • 命令模式撤销

思考命令模式

命令模式就是解耦强耦合代码,用户只关心功能的实现,开发者却可以利用命令模式在这之间加一些小动作,比如:撤销命令、命令排队、记录命令日志等

1.命令模式的本质

命令模式的本质:封装请求。

命令模式的关键就是把请求封装成为命令对象,然后就可以对这个对象进行一系列的处理了,比如上面讲到的参数化配置、可撤销操作、宏命令、队列请求、日志请求等功能处理。

2.何时选用命令模式

建议在以下情况时选用命令模式。

  • 如果需要抽象出需要执行的动作,并参数化这些对象,可以选用命令模式。将这些需要执行的动作抽象成为命令,然后实现命令的参数化配置。

  • 如果需要在不同的时刻指定、排列和执行请求,可以选用命令模式。将这些请求封装成为命令对象,然后实现将请求队列化。

  • 如果需要支持取消操作,可以选用命令模式,通过管理命令对象,能很容易地实现命令的恢复和重做功能。

  • 如果需要支持当系统崩溃时,能将系统的操作功能重新执行一遍,可以选用命令模式。将这些操作功能的请求封装成命令对象,然后实现日志命令,就可以在系统恢复以后,通过日志获取命令列表,从而重新执行一遍功能。

  • 在需要事务的系统中,可以选用命令模式。命令模式提供了对事务进行建模的方法。命令模式有一个别名就是Transaction。

3.优缺点

命令模式的优点

  • 更松散的耦合
    命令模式使得发起命令的对象——客户端,和具体实现命令的对象——接收者对象完全解耦,也就是说发起命令的对象完全不知道具体实现对象是谁,也不知道如何实现。

  • 更动态的控制
    命令模式把请求封装起来,可以动态地对它进行参数化、队列化和日志化等操作,从而使得系统更灵活。

  • 很自然的复合命令
    命令模式中的命令对象能够很容易地组合成复合命令,也就是前面讲的宏命令,从而使系统操作更简单,功能更强大。

  • 更好的扩展性
    由于发起命令的对象和具体的实现完全解耦,因此扩展新的命令就很容易,只需要实现新的命令对象,然后在装配的时候,把具体的实现对象设置到命令对象中,然后就可以使用这个命令对象,已有的实现完全不用变化。

4.实现

耦合写法

模拟电脑开机,点击机箱开机按钮,调用主板初始化系统,然后用户就能操作了

主板类

/**
 * @description:主板接口
 */
public interface MainBoardApi {

    /**
     * 开机
     */
    void open();
}

/**
 * @description:技嘉主板
 */
public class JiJiaMainBoard implements MainBoardApi{

    @Override
    public void open() {
        System.out.println("技嘉主板正在开机,请稍后");
        System.out.println("接通电源.............");
        System.out.println("设备检查.............");
        System.out.println("装载系统.............");
        System.out.println("机器正常运行,请操作....");
    }
}

/**
 * @description:微星主板
 */
public class WeiXinMainBoard implements MainBoardApi{

    @Override
    public void open() {
        System.out.println("微星主板正在开机,请稍后");
        System.out.println("接通电源.............");
        System.out.println("设备检查.............");
        System.out.println("装载系统.............");
        System.out.println("机器正常运行,请操作....");
    }
}

开机按钮类

/**
 * @description:机箱开机按钮
 */
public class BoxButton {

    /**
     * 点击开机按钮,就开机
     */
    public void boot(int flag){
        if (1==flag){
            new JiJiaMainBoard().open();
        }else {
            new WeiXinMainBoard().open();
        }
    }
}

测试类

/**
 * @description:最开始耦合写法
 */
public class Test1 {

    public static void main(String[] args) {
        //点击按钮开机
        new BoxButton().boot(2);
    }
}

现在,机箱按钮直接调用主板,是强耦合的关系,很不利于维护
在这里插入图片描述

命令模式写法

改造上面的耦合写法,主板接口和实现类不变

调用程序类(也就是上面的机箱按钮)

/**
 * @description:调用程序(机箱开机按钮)
 */
public class Invoker {

    /**
     * 持有命令对象
     */
    private Command command=null;

    public void setCommand(Command command) {
        this.command = command;
    }

    /**
     * 开机
     */
    public void boot(){
        command.execute();
    }
}

命令类

/**
 * @description:命令接口
 */
public interface Command {

    /**
     * 执行命令
     */
    void execute();
}

/**
 * @description:具体命令类(这里是开机命令)
 */
@AllArgsConstructor
public class ConcreteCommand implements Command{

    /**
     * 持有主板对象
     */
    private MainBoardApi mainBoardApi;

    @Override
    public void execute() {
        //命令类不能进行开机操作
        //调用主板进行开机
        mainBoardApi.open();
    }
}

测试类

/**
 * @description:测试类
 * @createTime 2022/11/30 13:06
 */
public class Client {

    public static void main(String[] args) {
        //把命令和实现组装起来
        Command command=new ConcreteCommand(new WeiXinMainBoard());
        //为机箱按钮设置命令
        Invoker invoker = new Invoker();
        invoker.setCommand(command);
        //模拟开机按钮
        invoker.boot();
    }
}

效果
在这里插入图片描述

在这里插入图片描述

命令模式撤销

撤销有两种:

  • 补偿式(反操作式)
  • 存储恢复式

模拟假如存在一个存在一个撤销按钮,电脑开机后,点击撤销按钮,撤销开机操作,也就是进行关机

主板类增加关机功能

/**
 * @description:主板接口
 */
public interface MainBoardApi {

    /**
     * 开机
     */
    void open();

    /**
     * 关机
     */
    void close();
}

/**
 * @description:技嘉主板
 */
public class JiJiaMainBoard implements MainBoardApi{

    @Override
    public void open() {
        System.out.println("技嘉主板正在开机,请稍后");
        System.out.println("接通电源.............");
        System.out.println("设备检查.............");
        System.out.println("装载系统.............");
        System.out.println("机器正常运行,请操作....");
    }

    @Override
    public void close() {
        System.out.println("技嘉主板正在关机,请稍后");
        System.out.println("关机成功.............");
    }
}

/**
 * @description:微星主板
 */
public class WeiXinMainBoard implements MainBoardApi{

    @Override
    public void open() {
        System.out.println("微星主板正在开机,请稍后");
        System.out.println("接通电源.............");
        System.out.println("设备检查.............");
        System.out.println("装载系统.............");
        System.out.println("机器正常运行,请操作....");
    }

    @Override
    public void close() {
        System.out.println("微星主板正在关机,请稍后");
        System.out.println("关机成功.............");
    }
}

命令接口增加撤销命令

/**
 * @description:命令接口
 */
public interface Command {

    /**
     * 执行命令
     */
    void execute();

    /**
     * 撤销命令
     */
    void undo();
}

/**
 * @description:具体命令类(这里是开机命令)
 */
@AllArgsConstructor
public class ConcreteCommand implements Command{

    /**
     * 持有主板对象
     */
    private MainBoardApi mainBoardApi;

    @Override
    public void execute() {
        //命令类不能进行开机操作
        //调用主板进行开机
        mainBoardApi.open();
    }

    @Override
    public void undo() {
        //撤销开机,也就是关机
        mainBoardApi.close();
    }
}

调用程序增加关机功能

/**
 * @description:调用程序(机箱开机按钮)
 */
public class Invoker {

    /**
     * 持有命令对象
     */
    private Command command=null;

    public void setCommand(Command command) {
        this.command = command;
    }

    /**
     * 开机
     */
    public void boot(){
        command.execute();
    }

    /**
     * 关机
     */
    public void shutdown(){
        command.undo();
    }
}

测试类

public class Client {

    public static void main(String[] args) {
        //把命令和实现组装起来
        Command command=new ConcreteCommand(new WeiXinMainBoard());
        //为机箱按钮设置命令
        Invoker invoker = new Invoker();
        invoker.setCommand(command);
        //模拟开机按钮
        invoker.boot();

        //模拟点击撤销按钮,电脑关机
        invoker.shutdown();
    }
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

天翎知识文档系统+群晖NAS,助力企业实现移动化学习

编者按:移动化学习成为一种社会发展趋势,本文分析了企业移动化学习的意义,并提出了企业移动化学习的一款全新解决方案——天翎知识文档系统群晖NAS。 关键词:多端适配,学习培训,智能问答,在线预…

Javascript脚本运算符执行顺序对照表

Javascript脚本运算符执行顺序对照表:在线查看Javascript脚本运算符执行优先级别 窍门: CtrlF 快速查找 Javascript脚本运算符优先级,是描述在计算机计算表达式时执行运算的先后顺序。Javascript脚本运算符优先级表,同一行中的运算…

巴西队提前出线,预定大力神杯?数据分析告诉你,到底谁才是冠军

2022年卡塔尔世界杯的第一轮小组赛,已经在众多惊诧、悲伤、惊喜的情绪中结束,而仅仅是第一轮的小组比赛,不断爆出的冷门就足以使人大跌眼镜了: 连续34场世界大赛不败的潘帕斯雄鹰——阿根廷,1-2负于世界排名51的沙特&…

天宇优配|百股涨停再现,沪指盘中创近两个月新高

周二A股商场呈现普涨格局,上证指数上涨2.31%,盘中最高点位创出最近两个月新高。各大职业板块近乎全线上涨,地产板块个股掀起涨停潮,数十只地产债盘中涨光临停。此外,A股大金融体现强势,疫苗股则尾盘忽然暴力…

号称Java圣经,Github上爆火的1058页JVM全栈小册到底有什么魅力

对于JVM,我想大部分小伙伴都是要面试了才会去学,其余时间基本不会去看(掐指一算,你们书架上面的深入理解Java虚拟机第三版应该都一层灰了吧【手动狗头】)。但值得一说的是,当你工作多年之后,你遇…

基于LSCF和LSFD算法在频域中识别快速实现的MIMO研究(Matlab代码实现)

👨‍🎓个人主页:研学社的博客 💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜…

TensorFlow Lite 是什么?用 TensorFlow Lite 来转换模型(附代码)

文章目录TensorFlow Lite 做了什么?将一个模型用 TensorFlow Lite 转换训练一个简易模型保存模型转换模型加载 TFLite 模型并分配张量进行预测将在猫狗大战数据集上进行迁移学习的 MobileNetV2 转换到 TensorFlow Lite将模型转换到 TensorFlow Lite优化模型Referenc…

DFL3:软件版本的选择和安装详解

这本是一个简单的问题,但是对于新手而言,所有问题,总是说的越清楚越仔细越好。我之所以这么说,肯定是有人问了。所以我就专门开一篇文章来说一说,软件版本的异同,以及如何选择。针对不同的语言,…

如何快速定位到报错日志中的关键信息,一招学会,赶快GET吧

一般的服务器日志一个可能大的有几十上百m,小的也得几百k,里面内容是比较多的,如拿到日志没思路去看的话,下面一些办法可以让你快速定位到日志中的异常错误信息 文章目录步骤1:定位到错误信息再那个日志中(grep)步骤2:查看日志上下…

[附源码]计算机毕业设计springboot教育企业网站

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

鲲鹏devkit性能分析工具介绍(三)

鲲鹏devkit性能分析工具介绍(三) 本篇主要讲解鲲鹏devkit性能分析工具的访存分析功能 访存分析 访存统计分析基于CPU访问缓存和内存的PMU事件,分析存储的访问次数、命中率、带宽等情况。 Miss事件分析基于ARM SPE(Statistical…

固话号码认证有什么好处?固话号码认证有什么作用?

固话号码认证为企业提供号码认证服务,在来电时显示企业信息,可提高电话号码辨识度,防止错误标记,确保展现的企业信息与企业的手机终端、APP等多平台展示信息一致,保证品牌企业的身份及商业价值。 那如何上线号码认证服…

图的初识·基本概念

文章目录基本概念图有两种基本形式无向图的表示有向图的表示基本概念 图结构也是数据结构的一部分。而且还有一点小难。图是由多个结点链接而成的,但是一个结点可以同时连接多个其他结点,多个节点也可以同时指向一个节点。【多对多的关系】 图结构是任意…

iPhone升级iOS 16后出现提示“面容ID不可用”怎么办?

最近,很多用户在苹果社区反馈,iPhone升级iOS 16后Face ID不能用了,尝试重置Face ID时,系统会弹窗提示“面容ID不可用,稍后尝试设置面容ID。” 如果你的iPhone在没有摔落手机或是手机进水的情况下出现这个弹窗&#xff…

电脑游戏录屏哪个好用免费?这2款录屏软件,用过都说好!

​相信很多小伙伴都有过在游戏中的精彩操作吧。有些小伙伴想要把自己在游戏中的精彩操作分享给朋友,可是却不知道有什么好用免费的游戏录屏软件,能够将自己游戏里的亮眼表现录制下来。那么电脑游戏录屏哪个好用免费?接下来小编分享2款永久免费…

PyQt5 窗口数据传递

PyQt5 窗口数据传递单一窗口数据传递多窗口数据传递:调用属性多窗口数据传递:信号与槽开发应用程序时,若只有一个窗口则只需关心这个窗口里面的各控件之间如何传递数据。如果程序有多个窗口,就要关心不同的窗口之间是如何传递数据…

History、Location

History、Location 学习路线:JavaScript_BOM->Window对象->confirm()、setInterval()、setTimeout()->History、Location->闪烁的灯泡 History History 对象是 JavaScript 对历史记录进行封装的对象。 History 对象的获取 使用 window.history获取&a…

云小课|云小课教您如何选择Redis实例类型

阅识风云是华为云信息大咖,擅长将复杂信息多元化呈现,其出品的一张图(云图说)、深入浅出的博文(云小课)或短视频(云视厅)总有一款能让您快速上手华为云。更多精彩内容请单击此处。 摘要:购买Redis实例时,实例类型有单机、主备、Pr…

vmware安装openEuler20.03

一,直接看图。 点击创建虚拟机。 这里如果是21.03版本的话,版本需要选择Linux5.x内核64位。 20.03选择Linux4.x的内核。 2个或者4个都行。 内存不要小于4G。 官方推荐不要小于32G。 直接下一步即可。 然后等待,进入配置。 安…

数据结构学习:Trie树

Trie一、概念二、代码实现三、Tire树的时间复杂度和空间复杂度四、Tire树的优势一、概念 Trie树,也叫"字典树",顾名思义,是一种专门处理字符串匹配的树形结构,用来解决在一组字符串集合中快速找到某个字符串类似于这种字符串匹配问题,可以使用RF暴力匹配、RK哈希匹配…