设计模式之命令模式

news2024/11/26 3:29:56

Command design pattern

命令模式的概念、命令模式的结构、命令模式的优缺点、命令模式的使用场景、命令模式的实现示例、命令模式的源码分析


1、命令模式的概念

  命令模式,即将请求封装成一个对象,使发出请求的责任和执行请求的责任分离开。这样两者之间通过命令对象进行沟通,方便讲命令对象进行存储、传递、调用和管理。

2、命令模式的结构

  • 抽象命令:定义执行命令的行为。
  • 实现者/接受者:命令的实现者或接受者,真正执行命令的对象。任何类都可以成为一个接受者,只要它能够实现命令所要求的功能。
  • 具体命令:实现抽象命令,持有接受者的引用,通过委托调用接受者执行命令的方法来实现命令的行为。
  • 调用者/请求者:即命令请求,命令发起者,持有命令对象的引用,它可以持有多个命令,即可以一次性发出多个命令。它是客户端真正出发命令并要求命令执行的地方,也就是相当于使用命令对象的入口。

command-class

3、命令模式的优缺点

  • 优点:
    • 降低系统的耦合度。即降低命令请求者与执行者的耦合度。
    • 满足开闭原则,增加命令或删除命令不影响其它类,扩展灵活。
    • 可实现宏命令,命令模式可与组合模式结合,将多个命令装配成一个组合命令,即宏命令。
    • 方便实现 Undo 和 Redo 操作,命令模式可与备忘录模式结合,实现命令的撤销和恢复。
  • 缺点:
    • 导致系统有过多的具体命令类,增加系统复杂度。

4、命令模式的使用场景

  • 当需要讲请求者调用者和请求接受者解耦时。
  • 当需要在不同的时间指定请求,将请求排队和执行请求。
  • 当需要支持命令的撤销操作和恢复操作时。

5、命令模式的实现示例

接受者:

public class Receiver {

    /**
     * 命令接受者执行命令
     * @param name
     */
    public void attack(String name) {
        System.out.println(name);
    }
}

抽象命令:

public interface Command {

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

具体命令:

public class ZedCommand implements Command {

    private String name;

    private Receiver receiver;

    public ZedCommand(String name, Receiver receiver) {
        this.name = name;
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        receiver.attack(this.name);
    }
}

调用者:

public class Invoker {

    private List<Command> commands;

    public Invoker() {
        this.commands = new ArrayList<>();
    }

    public void addCommand(Command command) {
        this.commands.add(command);
    }

    /**
     * 发出命令
     */
    public void commands() {
        for (Command command : this.commands) {
            command.execute();
        }
    }
}

测试:

public class CommandTest {

    public static void main(String[] args) {
        Invoker invoker = new Invoker();

        Receiver receiver = new Receiver();

        invoker.addCommand(new ZedCommand("禁奥义·瞬狱影杀阵", receiver));
        invoker.addCommand(new ZedCommand("影奥义·分身", receiver));
        invoker.addCommand(new ZedCommand("影奥义·鬼斩", receiver));
        invoker.addCommand(new ZedCommand("影奥义·诸刃", receiver));
        invoker.addCommand(new ZedCommand("影奥义·分身", receiver));
        invoker.addCommand(new ZedCommand("影忍法·灭魂劫", receiver));
        invoker.addCommand(new ZedCommand("禁奥义·瞬狱影杀阵", receiver));

        invoker.commands();
    }
}

测试结果:

禁奥义·瞬狱影杀阵
影奥义·分身
影奥义·鬼斩
影奥义·诸刃
影奥义·分身
影忍法·灭魂劫
禁奥义·瞬狱影杀阵

6、命令模式的源码分析

  jdk 中的 Runnable 接口的设计就是一个典型的命令模式。Runnable 接口担当命令角色,Thread 则是调用者,start 方法就是命令执行方法。

// 抽象命令
public interface Runnable {
  	// 执行命令
    public abstract void run();
}
public class Thread implements Runnable {
  	// 持有命令的引用
  	private Runnable target;
  public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

    private native void start0();
}

  通过源码可以发现,其在发出命令调用时会调用一个本地方法 start0(),开启一个县城。而接受者是对外开放的,即程序员可以自己定义接受者。

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

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

相关文章

App自动化测试【1】Appium的原理解读

1.Appium的架构原理 Appium的架构原理如图所示&#xff0c;由客户端&#xff08;Appium Client&#xff09;和服务器&#xff08;Appium Server&#xff09;两部分组成&#xff0c;客户端与服务器端通过JSON Wire Protocol进行通信。 2.Appium原理解读 客户端Client&#x…

Win10自动更新怎么永久关闭?服务、注册表、组策略、计划任务中全方位设置,永久解决!

Win10自动更新就像打不死的小强&#xff0c;不管怎么关闭&#xff0c;之后还是会自动更新&#xff0c;让不少小伙伴颇为不爽。今天通过4步&#xff0c;在服务、注册表、组策略、计划任务中全方位设置&#xff0c;彻底关闭Win10自动更新&#xff0c;感兴趣的小伙伴不妨试试吧。 …

Python:requirements.txt, environment.yml简介

文章目录简介requirements.txtenvironment.yml小结简介 最近安装了一些从github上clone下载的开源python软件包&#xff0c;经历了许许多多的酸甜苦辣。在python软件包&#xff0c;通常都会包含requirements.txt, environment.yml, setup.py三者之中某些或者全部&#xff0c;一…

11.注解开发依赖注入及管理第三方Bean

1. 注解开发依赖注入 1.1 使用Autowired注解开启自动装配模式 Service public class BookServiceImpl implements BookService {//Autowired&#xff1a;注入引用类型&#xff0c;自动装配模式&#xff0c;默认按类型装配Autowiredprivate BookDao bookDao;public void save(…

【OpenCV+Qt】实现简易视频播放器——支持进度条拖动

OpenCV实现视频播放器&#xff0c;其思路大致就是在线程中使用OpenCV中的VideoCapture循环读取本地视频的每一帧Mat&#xff0c;然后发送到界面转换成QImage进行显示&#xff0c;而进度条拖动则用到了VideoCapture中的set函数&#xff0c;进度条则是使用Qslider&#xff1b;并且…

记录安装 fenics 的问题

因为 fenics 官方更新后可能版本会出现有时效的问题, 所以也记录一下时间. Windows 系统下安装最大的问题 2022-12-19 记录. Windows 系统下本来是想通过 Anaconda 安装 fenics 的, 创建好虚拟环境后, 利用 conda install -c conda-forge fenics 进行安装, 但是直接提示 Pack…

操作系统,计算机网络,数据库刷题笔记14

操作系统&#xff0c;计算机网络&#xff0c;数据库刷题笔记14 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xf…

【OpenSourceC#】ET框架

1. 前言 ET算是我刚接触客户端时最早知道的框架&#xff0c;ET我最初眼馋的还是他的双端功能。包揽前后端的功能&#xff0c;这个很有吸引力。但是那时候对我来说这框架太复杂了&#xff0c;没法看。 这两天又来看看&#xff0c;曾经很多不懂的地方现在都能看懂了&#xff0c…

数据库拆分5--使用sharding-jdbc来实现水平拆分

有三张表 user log order表&#xff0c;先将user log 和order垂直分库&#xff0c;然后将user表水平拆分 配置文件 spring.shardingsphere.enabledtruespring.shardingsphere.datasource.nameswim-user,wim-orderspring.shardingsphere.datasource.wim-user.typecom.alibaba.…

【JavaEE】多线程之Thread类

一、Thread类常见方法与字段 1、构造方法 构造方法说明Thread()不带参数的构造方法Thread(String name)可以在构造时传入线程的名字Thread(Runnable run)传入Runnable&#xff0c;是创建线程的方法之一Thread(Runnable run,String name)传入线程工作并给线程起名 2、常见属性…

JaveWeb框架(一):Web入门,Http的请求和响应,https介绍,Web实战自定义服务器

Servlet入门 MVC实战项目 仓储管理系统JavaWeb入门介绍Http协议Http请求数据格式Http响应数据格式Web实战Demo&#xff1a;自定义服务器对比Https协议总结Redis章节复习已经过去&#xff0c;新的章节JavaWeb开始了&#xff0c;这个章节中将会回顾JavaWeb实战项目 仓储管理 代码…

机器人开发--电机中的电流环、速度环、位置环

机器人开发--电机中的电流环、速度环、位置环电流环、速度环、位置环1 三环原理1.1 电流环1.2 速度环1.3 位置环2 各环与PID控制2.1 电流环重点在 PID&#xff08;比例、积分和微分&#xff09;2.2 速度环重点在 PI&#xff08;比例和积分&#xff09;2.3 位置环重点在 P&#…

基于JAVA的企业部门报销管理信息系统的设计与实现

开发工具(eclipse/idea/vscode等)&#xff1a; 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a; 系统部分主要分为以下几个模块&#xff1a;公告类型&#xff0c;公告信息&#xff0c;部门信息&#xff0c;员工信 息&a…

手写Spring9(实现FactoryBean、对象作用域)

文章目录前言目标设计项目结构一、实现1、Bean的作用范围定义和xml解析2、创建和修改对象时候判断单例和原型模式3、定义 FactoryBean 接口4、实现一个 FactoryBean 注册服务5、扩展 AbstractBeanFactory 创建对象逻辑二、测试1、事先准备2、定义 FactoryBean 对象3、配置文件4…

Win32多线程调用gdal库接口

作者:朱金灿 来源:clever101的专栏 为什么大多数人学不会人工智能编程?>>> 效果图和程序说明 效果图如下:   这个程序是基于MFC的GUI程序,用于给指定的文件夹批量创建金字塔。   效果图如下:   这个程序是基于Win32 API的GUI程序,用于给指定的文件创…

期末前端web大作业——动漫客栈响应式bootstarp(7页) 排版整洁,内容丰富,主题鲜明

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置&#xff0c;有div的样式格局&#xff0c;这个实例比较全面&#xff0c;有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 ⚽精彩专栏推荐&#x1…

R语言用线性回归模型预测空气质量臭氧数据

尽管线性模型是最简单的机器学习技术之一&#xff0c;但它们仍然是进行预测的强大工具。 最近我们被客户要求撰写关于线性回归模型的研究报告&#xff0c;包括一些图形和统计输出。 这尤其是由于线性模型特别容易解释这一事实。在这里&#xff0c;我将讨论使用空气质量数据集…

Python学习基础笔记五十四——多继承

多继承中&#xff0c;我们子类对象调用的一个方法&#xff0c;默认是就近原则&#xff0c;找的顺序是什么&#xff1f; 在经典类中&#xff0c;是深度优先&#xff1b; 在新式类中&#xff0c;是广度优先&#xff1b; Python2.7是经典类和新式类共存&#xff0c;新式类要继承…

领域模型设计模式

前言&#xff1a; 领域是一个组织所做的事情以及其包含的一切&#xff0c;通俗地说&#xff0c;就是组织的业务范围和做事情的方式&#xff0c;也是软件开发的目标范围。比如说淘宝的电商业务&#xff0c;C2C就是电子商务的领域&#xff0c;领域驱动设计就是从领域出发&#x…

安装VS code

五 安装VS Code Visual Studio Code&#xff0c;简称VS Code&#xff0c;是一种简化且高效的代码编辑器&#xff0c;同时支持诸如调试&#xff0c;任务执行和版本管理之类的开发操作。它的目标是提供一种快速的编码编译调试工具。优势&#xff1a; 支持多种语言的编写&#xf…