Java设计模式 13-命令模式

news2024/12/23 19:01:35

命令模式

一、智能生活项目需求

看一个具体的需求

image-20210702203204437

1)我们买了一套智能家电,有照明灯、风扇、冰箱、洗衣机,我们只要在手机上安装 app 就可以控制对这些家电工作。

2)这些智能家电来自不同的厂家,我们不想针对每一种家电都安装一个 App,分别控制,我们希望只要一个 app

就可以控制全部智能家电。

3)要实现一个 app 控制所有智能家电的需要,则每个智能家电厂家都要提供一个统一的接口给 app 调用,这时 就可以考虑使用命令模式。

4)命令模式可将 “动作的请求者”从“动作的执行者”对象中解耦出来.

5)在我们的例子中,动作的请求者是手机 app,动作的执行者是每个厂商的一个家电产品

二、命令模式基本介绍

1)命令模式(Command Pattern):

在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计

2)命名模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦

3)在命名模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求(即命名),同时命令模式也支持可撤销的操作。

4)通俗易懂的理解:

将军发布命令,士兵去执行。其中有几个角色:将军(命令发布者)、士兵(命令的具体执行者)、命令(连接将军和士兵)。Invoker 是调用者(将军),Receiver 是被调用者(士兵),MyCommand 是命令,实现了 Command 接口,持有接收对象

三、 命令模式的原理类图

image-20210702221715800

  • 对原理类图的说明-即(命名模式的角色及职责)

1)Invoker 是调用者角色

2)Command: 是命令角色,需要执行的所有命令都在这里,可以是接口或抽象类

3)Receiver: 接受者角色,知道如何实施和执行一个请求相关的操作

4)ConcreteCommand: 将一个接受者对象与一个动作绑定,调用接受者相应的操作,实现 execute

四、命令模式解决智能生活项目

  • 应用实例要求

1)编写程序,使用命令模式 完成前面的智能家电项目

2)思路分析和图解

image-20210702224329106

3)代码实现

主函数

public class Client {
    public static void main(String[] args) {
        //使用命令设计模式,完成通过遥控器,对电灯的操作
        //创建电灯的对象(接受者)
        LightReceiver lightReceiver = new LightReceiver();

        //创建电灯相关的开关命令
        LightOnCommand lightOnCommand = new LightOnCommand(lightReceiver);
        LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver);

        //需要一个遥控器
        RemoteController remoteController = new RemoteController();

        //给我们的遥控器设置命令, 比如 no = 0  是电灯的开和关的操作
        remoteController.setCommand(0, lightOnCommand, lightOffCommand);
        System.out.println("--------按下灯的开按钮-----------"); remoteController.onButtonWasPushed(0); 
        System.out.println("--------按下灯的关按钮-----------"); remoteController.offButtonWasPushed(0); 
        System.out.println("--------按下撤销按钮-----------"); remoteController.undoButtonWasPushed();

        System.out.println("=========使用遥控器操作电视机=========="); 
        TVReceiver tvReceiver = new TVReceiver();

        TVOffCommand tvOffCommand = new TVOffCommand(tvReceiver); 
        TVOnCommand tvOnCommand = new TVOnCommand(tvReceiver);

        //给我们的遥控器设置命令, 比如 no = 1  是电视机的开和关的操作
        remoteController.setCommand(1, tvOnCommand, tvOffCommand);

        System.out.println("--------按下电视机的开按钮-----------");
        remoteController.onButtonWasPushed(1); 
        System.out.println("--------按下电视机的关按钮-----------"); remoteController.offButtonWasPushed(1); 
        System.out.println("-------- 按 下 撤 销 按 钮 -----------"); 
        remoteController.undoButtonWasPushed();
    }
}

Command

//创建命令接口
public interface Command {
    //执行动作(操作) 
    public void execute();
    //撤销动作(操作) 
    public void undo();
}

LightOffCommand

public class LightOffCommand implements Command {
    // 聚合关系 
    LightReceiver light;
    
    // 构造器
    public LightOffCommand(LightReceiver light) { 
        super();
        this.light = light;
    }

    @Override
    public void execute() {
        // 调用接收者的方法
        light.off();
    }

    @Override
    public void undo() {
        // 调用接收者的方法
        light.on();
    }
}

LightOnCommand

public class LightOnCommand implements Command {
    //聚合关系 
    LightReceiver light;
    //构造器
    public LightOnCommand(LightReceiver light) { 
        super();
        this.light = light;
    }

    @Override
    public void execute() {
        //调用接收者的方法 
        light.on();
    }

    @Override
    public void undo() {
        //调用接收者的方法
        light.off();
    }
}

LightReceiver

public class LightReceiver {
    public void on() {
        System.out.println(" 电灯打开了.. ");
    }

    public void off() {
        System.out.println(" 电灯关闭了.. ");
    }
}

NoCommand

/**
*	没有任何命令,即空执行: 用于初始化每个按钮, 当调用空命令时,对象什么都不做
*	其实,这样是一种设计模式, 可以省掉对空判断
*	@author Administrator*
*/
public class NoCommand implements Command {
    @Override
    public void execute() {
    }

    @Override
    public void undo() {
    }
}

RemoteController

public class RemoteController {
    // 开 按钮的命令数组
    Command[] onCommands; 
    Command[] offCommands;

    // 执行撤销的命令
    Command undoCommand;

    // 构造器,完成对按钮初始化
    public RemoteController() {
        onCommands = new Command[5]; 
        offCommands = new Command[5];
        for (int i = 0; i < 5; i++) {
            //对5个开按钮,5个关按钮,进行 空操作 初始化
            onCommands[i] = new NoCommand(); 
            offCommands[i] = new NoCommand();
        }
    }

    // 给我们的按钮设置你需要的命令
    //int no:第几组
    public void setCommand(int no, Command onCommand, Command offCommand) { 
        onCommands[no] = onCommand;
        offCommands[no] = offCommand;
    }

    // 按下开按钮
    public void onButtonWasPushed(int no) { // no 0
        // 找到你按下的开的按钮, 并调用对应方法
        onCommands[no].execute();
        // 记录这次的操作,用于撤销
        undoCommand = onCommands[no];
    }

    // 按下关按钮
    public void offButtonWasPushed(int no) { // no 0
        // 找到你按下的关的按钮, 并调用对应方法
        offCommands[no].execute();
        // 记录这次的操作,用于撤销
        undoCommand = offCommands[no];
    }

    // 按下撤销按钮
    public void undoButtonWasPushed() { 
        undoCommand.undo();
    }
}

TVOffCommand

public class TVOffCommand implements Command {
    // 聚 合 TVReceiver
    TVReceiver tv;

    // 构造器
    public TVOffCommand(TVReceiver tv) { 
        super();
        this.tv = tv;
    }

    @Override
    public void execute() {
        // 调用接收者的方法
        tv.off();
    }

    @Override
    public void undo() {
        // 调用接收者的方法
        tv.on();
    }
}

TVOnCommand

public class TVOnCommand implements Command {
    // 聚 合 
    TVReceiver tv;
    // 构造器
    public TVOnCommand(TVReceiver tv) { 
        super();
        this.tv = tv;
    }

    @Override
    public void execute() {
        // 调用接收者的方法
        tv.on();
    }

    @Override
    public void undo() {
        // 调用接收者的方法
        tv.off();
    }
}

TVReceiver

public class TVReceiver {
    public void on() {
        System.out.println(" 电视机打开了.. ");
    }

    public void off() {
        System.out.println(" 电视机关闭了.. ");
    }
}

五、命令模式的注意事项和细节

1)将发起请求的对象与执行请求的对象解耦。发起请求的对象是调用者,调用者只要调用命令对象的 execute()方法就可以让接收者工作,而不必知道具体的接收者对象是谁、是如何实现的,命令对象会负责让接收者执行请求的动作,也就是说:”请求发起者”和“请求执行者”之间的解耦是通过命令对象实现的,命令对象起到了纽带桥梁的作用

2)容易设计一个命令队列。只要把命令对象放到列队,就可以多线程的执行命令

3)容易实现对请求的撤销和重做

4)命令模式不足:

可能导致某些系统有过多的具体命令类,增加了系统的复杂度,这点在在使用的时候要注意

5)空命令也是一种设计模式,它为我们省去了判空的操作。在上面的实例中,如果没有用空命令,我们每按下一个按键都要判空,这给我们编码带来一定的麻烦。

6)命令模式经典的应用场景:

界面的一个按钮都是一条命令、模拟 CMD(DOS 命令)订单的撤销/恢复、触发- 反馈机制

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

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

相关文章

怎样实现RPC框架

随着微服务架构的盛行&#xff0c;远程调用成了开发微服务必不可少的能力&#xff0c;RPC 框架作为微服务体系的底层支撑&#xff0c;也成了日常开发的必备工具。当下&#xff0c;RPC 框架已经不仅是进行远程调用的基础工具&#xff0c;还需要提供路由、服务发现、负载均衡、容…

两种QGraphicsItem方式实现橡皮擦功能(矩形选中框)

方法一&#xff1a;继承QGraphicsItem实现橡皮擦功能。&#xff08;gif中红色矩形框&#xff09; 方法二&#xff1a;继承QGraphicsRectItem实现的橡皮擦功能。&#xff08;gif中蓝色矩形框&#xff09; 通过以上GIF可以看出两款橡皮擦都具有位置拖动和大小拖动的功能&#xff…

Nacos必知必会:这些知识点你一定要掌握!

前言 Nacos 是一个开源的服务发现、配置管理和服务治理平台&#xff0c;是阿里巴巴开源的一款产品。 Nacos 可以帮助开发者更好地管理微服务架构中的服务注册、配置和发现等问题&#xff0c;提高系统的可靠性和可维护性。 本文将介绍 Nacos 的必知必会知识点&#xff0c;包括…

Zookeeper基础和简单使用

安装与配置 概念 基于观察者模式设计的分布式服务管理框架&#xff0c;负责存储和管理大家都关心数据&#xff0c;然后接受观察者的注册&#xff0c;一单这些数据的这状态发生了变化&#xff0c;Zookeeper就将负责通知已经在Zookeeper上注册的那些观察者做出相应的反应 特点…

当JS遇到加密:解密你的JS代码!

作为一名程序员&#xff0c;我们经常会遇到各种加密算法&#xff0c;比如常见的AES、RSA、MD5等等&#xff0c;但是今天我想和大家聊一聊一个日常生活中比较常见的加密方式——JavaScript加密。 在我们日常浏览网页时&#xff0c;经常会看到一些网站的JavaScript代码经过加密&…

【Redis】布隆过滤器原理与应用

文章目录 原理应用实战总结 布隆过滤器&#xff08;Bloom Filter&#xff09;是 1970 年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。 它的优点是空间效率和查询时间都比一般的算法要好的多&#xff…

AJAX实现搜索联想 自动补全

分析: 1.想实现联想搜索需要数据库的数据支撑,需要进行模糊查询,搜索出所有包含用户输入的关键字信息,并将这些信息都反馈到前端,简化用户输入,从而提高用户的体验。 2.为了提高用户的使用体验&#xff0c;整个页面不能全部刷新&#xff0c;需要局部刷新&#xff0c;为此需要…

Python中的各种报错-一般错误

目录 ValueError: check_hostname requires server_hostname missing 1 required positional argument: self xxx is not a package libpng warning: iCCP: cHRM chunk does not match sRGB check_hostname requires server_hostname python 安装第三方库&#xff0c;超时…

MQTTC数据桥接上云

[小 迪 导 读]&#xff1a;在工业物联网蓬勃发展的背景下&#xff0c;私有化部署已经不能满足当前的发展趋势了&#xff0c;因此dgiot在原有基础上进行创新&#xff0c;将私有化部署的区域数控一体机上的数据通过mqtt桥接的方式上传到云服务器上&#xff0c;完成数据的实时同步…

Baumer工业相机堡盟工业相机软件CameraExplorer常见功能使用说明一

Baumer工业相机堡盟工业相机软件CameraExplorer常见功能使用说明一 Baumer工业相机Baumer工业相机图像采集功能Baumer工业相机图像基本参数设置 Baumer工业相机 Baumer工业相机堡盟相机是一种高性能、高质量的工业相机&#xff0c;可用于各种应用场景&#xff0c;如物体检测、…

【前端提效】-- Chrome浏览器开发者工具使用技巧

介绍一下 DevTools 的一些好用的技巧&#xff0c;它能够很好地帮助你提高生产力和解决问题的能力。 1、打开命令行 或者使用&#xff1a;快捷键 Ctrl Shift P (Mac&#xff1a; ⌘ Shift P ) 命令行可以做很多事情&#xff0c;包括但不限于截图、更换主题等 2、控制 DevT…

暑假线上兼职:300-500元/小时,安利一个大学生也能月入8K的线上兼职

在后台经常收到这样的留言&#xff1a; 快接近暑假了&#xff0c;有没有线上兼职推荐&#xff1f; 如何提升自己的眼界和能力&#xff0c;为之后的职场铺路&#xff1f; 不知道有多少朋友是想提升自己获取资源信息的速度&#xff0c;发展自己的爱好&#xff0c;或者增加第二收入…

用友U8增加查询条件

1、检查要增加的条件是否在该表单中&#xff1b; 2、在查询条件中增加查询条件的管理方案 3、参照ID就是要参照的表 4、数据源&#xff0c;在要增加的表单数据库中查询该字段名&#xff0c;进行增加即可。 select * from purbillvouch where cpbvcode 0000000312 --PurBillV…

调用legend资源,生成地图图例

作者&#xff1a;lly 文章目录 前言一、接口详情二、具体实现三、结果展示 前言 最近很多小伙伴资源关于iServer图例的问题&#xff0c; 接下来我们就来介绍下如何使用iServer legend资源&#xff0c;生成地图图例 一、接口详情 请求示例 {"layerLegends": [{&quo…

达索的天线设计和仿真软件Antenna Magus 2023版本下载与安装配置教程

目录 前言一、Antenna Magus安装二、使用配置总结 前言 Antenna Magus软件是一款用于天线设计和仿真的软件&#xff0c;提供了一个全面的设计工具集&#xff0c;帮助工程师优化天线设计&#xff0c;同时减少设计周期。 Antenna Magus的主要特点&#xff1a; ——高级天线库&…

如何用 ChatGPT 帮你自动分析数据?

误判 好几天之前&#xff0c;我就在 ChatGPT 选单里看到了 Code Interpreter。它正在灰度测试中 —— 先给一部分用户试用&#xff0c;如果反响不错并做了一定改进&#xff0c;就能推广给更多用户。 可惜当时我没能正确理解它的含义&#xff0c;犯了一个大错误 —— 望文生义。…

ChatGPT 上线联网和插件功能;投资者看好新版搜索引擎

&#x1f680; ChatGPT 上线联网和插件功能 OpenAI宣布将在这周推出联网和插件功能&#xff0c;位于Alpha和Beta通道的ChatGPT Plus用户都可使用70多个上线的插件。 更新意味着ChatGPT将利用最新的信息和资讯为使用者提供服务。 上线的ChatGPT插件种类涵盖了行程安排助理、代…

Android开发-Android常用组件-Date Time组件

4.11 Date & Time组件 1.TextClock(文本时钟) TextClock是在Android 4.2(API 17)后推出的用来替代DigitalClock的一个控件&#xff01; TextClock可以以字符串格式显示当前的日期和时间&#xff0c;因此推荐在Android 4.2以后使用TextClock。 这个控件推荐在24进制的and…

[内网]RDP远程桌面密码凭证获取

文章目录 RDP保存凭据通过注册表查看当前主机本地连接过的目标机器记录查看当前主机保存的RDP凭据查看本地用户是否存有RDP密码文件通过密码文件获取guidMasterKey的值根据guidMasterKey找到对应Masterkey解密获取明文以上总结&#xff1a; 在授权渗透过程中&#xff0c;如果获…

PCB当中的跳线有什么作用

在PCB设计中&#xff0c;跳线是一种常见的连接方式。跳线是为了连接电路中的距离较远或无法直接连接的电路元件而设置的&#xff0c;其作用是非常重要的。在本文中&#xff0c;我们将探讨PCB中跳线的作用和应用。 一、什么是跳线 跳线是一种特殊的电路连接方式&#xff0c;它是…