java设计模式学习之【命令模式】

news2025/2/4 22:05:22

文章目录

  • 引言
  • 命令模式简介
    • 定义与用途
    • 实现方式
  • 使用场景
  • 优势与劣势
  • 在Spring框架中的应用
  • 股票示例
  • 代码地址

引言

想象一下,你在一个忙碌的厨房里,厨师们正忙于准备各种菜肴。每当服务员带来一个新订单时,他们不会直接对厨师说需要做什么菜。相反,订单被写在纸上,并放置在一个订单队列中。厨师们会一个接一个地取订单,并准备相应的菜肴。这里,每个订单就像是一个“命令”,它包含了需要执行的所有信息。在软件开发中,我们处理命令时也可以采取类似的方式。命令模式允许我们以同样的方式封装所有信息,这些信息需要执行某项操作或触发某个事件,然后像传递订单一样传递这些命令。

命令模式简介

定义与用途

命令模式(Command Pattern)是一种行为型设计模式,它将一个请求或简单操作封装为一个对象。这种模式允许用户根据不同的请求将方法调用、请求或操作封装到单独的对象中,并将这些对象传递给调用者。调用者随后可以根据需求执行这些操作。这种模式通常用于:队列操作、回调操作和对请求的日志记录。

实现方式

实现命令模式涉及以下几个关键组件:

  • 命令接口(Command):定义了执行操作的接口。
  • 具体命令(Concrete Command):实现命令接口,定义接收者上执行的动作。
  • 接收者(Receiver):执行与请求相关联的操作。
  • 调用者(Invoker):持有命令,并在某个时间点调用命令的执行方法。
  • 客户端(Client):创建具体命令,并设置其接收者。

使用场景

命令模式适用于以下场景:
当需要将请求发送者和请求接收者解耦时。
当需要对请求的排队、记录或可撤销操作时。
在需要支持宏命令和事务系统的场景中。

例如:

  1. GUI按钮和菜单项:GUI的按钮和菜单项通常使用命令模式来处理用户输入。
  2. 事务型行为:命令模式可以用来实现事务系统,其中命令有执行和回滚两种操作。
  3. 多级撤销功能:在支持撤销操作的系统中,命令模式可以用来记录操作的历史,以便用户可以撤销或重做它们。

优势与劣势

  • 优势
    降低系统的耦合度:命令模式将调用操作的对象与知道如何实施该操作的对象解耦。
    增强了扩展性:可以很容易地增加新的命令。
    可以组合命令:可以组合多个命令,实现复杂的功能。
  • 劣势
    可能会导致某些系统有过多的具体命令类。

在Spring框架中的应用

JdbcTemplate 是Spring框架中使用命令模式的一个很好的例子。在JdbcTemplate的上下文中,命令模式提供了一种强大的机制来抽象和封装对数据库的各种操作。它允许JdbcTemplate通过执行各种StatementCallback实现来灵活地执行各种操作,同时保持其自身的简洁和不涉及具体数据库操作的逻辑。

(1)命令接口(Command)- StatementCallback
StatementCallback<T>接口 在这个上下文中类似于命令模式中的命令接口。它定义了一个doInStatement(Statement stmt)方法,该方法接收一个Statement对象作为参数。不同的实现将对数据库执行不同的操作。
(2)具体命令和接收者 - QueryStatementCallBack和其他实现
具体命令 由实现StatementCallback接口的类表示,例如QueryStatementCallBack。这些类封装了对数据库执行特定操作的逻辑。
同时充当命令接收者:在这种情况下,具体命令类(例如QueryStatementCallBack)不仅表示命令,还包含执行命令所需的逻辑,因此它们也扮演了接收者的角色。它们知道如何操作数据库来执行特定的操作。
(3)命令调用者 - JdbcTemplate
JdbcTemplate 是命令调用者。它提供了一个execute方法,该方法接受一个StatementCallback对象。JdbcTemplate不关心StatementCallback的具体操作,它只调用doInStatement方法并传递必要的Statement对象。这样,JdbcTemplate就可以执行各种不同的数据库操作,而不需要知道具体的细节。
(4)不同的具体命令实现
StatementCallback的其他实现,如QueryStatementCallback,为不同类型的数据库操作提供了具体实现。每个实现都有自己独特的doInStatement方法,它们封装了如何使用传递给它们的Statement来执行操作。

股票示例

在这里插入图片描述
步骤 1:创建命令接口
首先定义了一个 Order 接口,作为命令的角色。

public interface Order {
   void execute();
}

这个接口定义了一个execute方法,所有的命令都将实现这个方法来执行它们的操作。

步骤 2:创建请求类
创建了一个 Stock 类,作为请求的角色。

public class Stock {
	
   private String name = "ABC";
   private int quantity = 10;

   public void buy(){
      System.out.println("股票 [ 名称: "+name+", 数量: " + quantity +" ] 购买了");
   }
   public void sell(){
      System.out.println("股票 [ 名称: "+name+", 数量: " + quantity +" ] 卖出了");
   }
}

这个类代表一个股票,有买入和卖出的操作。

步骤 3:创建具体命令类
创建了实现Order接口的具体命令类。

public class BuyStock implements Order {
   private Stock abcStock;

   public BuyStock(Stock abcStock){
      this.abcStock = abcStock;
   }

   @Override
   public void execute() {
      abcStock.buy();
   }
}

public class SellStock implements Order {
   private Stock abcStock;

   public SellStock(Stock abcStock){
      this.abcStock = abcStock;
   }
	
   @Override
   public void execute() {
      abcStock.sell();
   }
}

BuyStock和SellStock是具体的命令,分别代表购买股票和出售股票的操作。

步骤 4:创建命令调用者类
创建了一个 Broker 类,作为命令的调用者。

import java.util.ArrayList;
import java.util.List;

public class Broker {
   private List<Order> orderList = new ArrayList<Order>(); 

   public void takeOrder(Order order){
      orderList.add(order);		
   }

   public void placeOrders(){
      for (Order order : orderList) {
         order.execute();
      }
      orderList.clear();
   }
}

Broker 可以接受和存储命令,然后一次性执行这些命令。它通过调用每个命令的execute方法来执行命令。

步骤 5:使用 Broker 类来接受和执行命令

public class CommandPatternDemo {
   public static void main(String[] args) {
      Stock abcStock = new Stock();

      BuyStock buyStockOrder = new BuyStock(abcStock);
      SellStock sellStockOrder = new SellStock(abcStock);

      Broker broker = new Broker();
      broker.takeOrder(buyStockOrder);
      broker.takeOrder(sellStockOrder);

      broker.placeOrders();
   }
}

在这里插入图片描述
在这个客户端中,我们创建了买入和卖出股票的命令,然后通过Broker来执行它们。这个例子演示了命令模式如何用于参数化对象以及如何将请求排队等待执行。

代码地址

23种设计模式相关代码后续会逐步提交到github上,方便学习,欢迎指点:
代码地址
https://github.com/RuofeiSun/lf-23Pattern

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

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

相关文章

Tomcat报404问题解决方案大全(包括tomcat可以正常运行但是报404)

文章目录 Tomcat报404问题解决方案大全(包括tomcat可以正常运行但是报404)1、正确的运行页面2、报错404问题分类解决2.1、Tomcat未配置环境变量2.2、IIs访问权限问题2.3、端口占用问题2.4、文件缺少问题解决办法&#xff1a; Tomcat报404问题解决方案大全(包括tomcat可以正常运…

C# .Net学习笔记—— 加密和解密算法

一、四种加密方式 1、MD5不可逆加密 2、Des对称可逆加密 3、RSA非对称可逆加密 4、数字证书SSL 二、详解 1、MD5加密 public class MD5Encrypt{public static string Encrypt(string source, int length 32){if (string.IsNullOrEmpty(source)) return string.Empty;HashA…

KubeSphere应用【六】中间件部署

一、Mysql部署 1.1创建配置字典 [client] default-character-setutf8mb4 [mysql] default-character-setutf8mb4[mysqld] sql_modeSTRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION init_connectSET…

Redis 的键管理

一、Redis 数据库管理 Redis 是一个键值对&#xff08;key-value pair&#xff09;的数据库服务器&#xff0c;其数据保存在 src/server.h/redisDb 中(网上很多帖子说在 redis.h 文件中&#xff0c;但是 redis 6.x版本目录中都没有这个文件。redisDb 结构应该在 server.h文件中…

mysql SQL执行超时问题

show variables like max_execution_time 使用这个命令查看了&#xff0c;没有设置sql执行超时时间&#xff0c;那么大概率问题就出在阿里的Druid数据库连接池出了问题 尝试着socketTimeout由60000毫秒改成10000毫秒&#xff0c;果然执行了十几秒就超时报错了 socketTime…

【uniapp】uniapp中本地存储sqlite数据库保姆级使用教程(附完整代码和注释)

数据库请求接口封装 uniapp中提供了plus.sqlite接口&#xff0c;在这里我们对常用的数据库请求操作进行了二次封装 这里的dbName、dbPath、recordsTable 可以根据你的需求自己命名 module.exports {/** * type {String} 数据库名称*/dbName: salary,/*** 数据库地址* type {…

LVM系统逻辑卷

1.lvm的来源 我们在工作中经常遇到服务器存储数据的分区磁盘空间不够的情况&#xff0c;尤其是当我们的业务是视频的时候&#xff0c;大批量用户上传和下载视频&#xff0c;磁盘空间需要不停的调整。如果我们作为运维每天的工作就是加硬盘是不是有点扯&#xff0c;而且换硬盘的…

signaltap立即触发的错误解决方法

signaltap点下run analysis后没有等到触发条件满足就触发了&#xff0c;原因是触发方式设置错误&#xff0c;应修改触发方式&#xff1a; 将Trigger flow control 从State-based 改为Sequential。

Java学习系列(七)

1.Java多态 多态是同一个行为具有多个不同表现形式或形态的能力&#xff0c; 多态就是同一个接口&#xff0c;使用不同的实例而执行不同操作。 多态的优点 1. 消除类型之间的耦合关系2. 可替换性3. 可扩充性4. 接口性5. 灵活性6. 简化性 多态存在的三个必要条件 继承重写…

鸿蒙原生应用/元服务开发-Stage模型能力接口(九)下

ohos.app.ability.UIAbility (UIAbility)Caller 通用组件Caller通信客户端调用接口, 用来向通用组件服务端发送约定数据。 Caller.call call(method: string, data: rpc.Parcelable): Promise<void>; 向通用组件服务端发送约定序列化数据。 系统能力&#xff1a;Syste…

XML简介 (EXtensible Markup Language)

XML简介 (EXtensible Markup Language) 可扩展标记语言 特点 XML与操作系统、编程语言的开发平台无关实现不同系统之间的数据交换 作用 数据交互配置应用程序和网站Ajax基石 XML标签 XML文档内容由一系列标签元素组成 <元素名 属性名"属性值">元素内容&l…

关于时区处理策略

前端会通过 App-Id 请求头附带 客户端时区 信息 前端传入的如果是 字符串&#xff0c;会自动根据 请求的客户端时区 解析为对应的 日期 如果前端传入的是时间戳&#xff0c;则无需额外解析转换 如果是 商户后台、管理后台 都统一基于 商户所在国家的时区&#xff08;总台目前…

<九>JavaScript中函数,函数的定义方式,形参、实参和返回值

JavaScript中的函数&#xff0c;也是一个对象&#xff0c;函数对象有所有普通对象有的性质。还可以在这个对象中封装一些功能&#xff0c;保存一些代码&#xff0c;在需要的时候调用这些代码&#xff0c;用typeof查看时&#xff0c;会返回类型&#xff1a;function。 定义函数…

线程学习(2)

&#x1f495;"i need your breath"&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;线程学习(2) 前情回顾&#xff1a; 在上一篇博客中介绍到了进程与线程的区别&#xff0c;以及初步了解如何在Java实现多线程编程&#xff0c;通过内置的Thread类来…

eNSP错误40,原因三:windows10自带虚拟化软件Hyper-V

问题描述 Hyper-V软件与VirtualBox不兼容&#xff0c;一旦开启Hyper-V的话eNSP的路由器就会无法开启&#xff0c;显示ERROR 40 原理 大家注意看hypervisor的两种类型&#xff1a; 左边的是开启hypervisor的Type-1&#xff0c;hypervisor在启用的时候&#xff0c;宿主机也相…

SQL指南:掌握日期函数来查询和管理数据

文章目录 1. 引言2. 建立数据库表2.1 建表语句2.2 数据插入 查询案例3.1 查询当前日期的订单3.2 查询过去一周内的订单3.3 查询明天的日期3.4 查询今年的订单3.5 查询特定月份的订单 总结 1. 引言 在数据库管理中&#xff0c;处理日期和时间是一项基本但重要的任务。本指南将通…

Android笔记(十九):JetPack DataStore 之 Preferences DataStore

Jetpack DataStore 是一种数据存储解决方案&#xff0c;主要适用于小型数据的处理。它可以通过协议缓冲区存储键值对或类型化对象。DataStore 使用 Kotlin 协程和 Flow 以异步、一致的事务方式存储数据。DataStore有两种实现方式&#xff08;1&#xff09;Preferences DataStor…

如何搭建Web自动化测试框架?

在程序员的世界中&#xff0c;一切重复性的工作&#xff0c;都应该通过程序自动执行。「自动化测试」就是一个最好的例子。 随着互联网应用开发周期越来越短&#xff0c;迭代速度越来越快&#xff0c;只会点点点&#xff0c;不懂开发的手工测试&#xff0c;已经无法满足如今的…

Enge问题解决教程

目录 解决问题的一般步骤&#xff1a; 针对"Enge问题"的具体建议&#xff1a; 以下是一些普遍适用的解决问题的方法&#xff1a; 以下是一些更深入的Enge浏览器问题和解决办法&#xff1a; 浏览器性能问题&#xff1a; 浏览器插件与网站冲突&#xff1a; 浏览…

R语言中使用ggplot2绘制散点图箱线图,附加显著性检验

散点图可以直观反映数据的分布&#xff0c;箱线图可以展示均值等关键统计量&#xff0c;二者结合能够清晰呈现数据蕴含的信息。 本篇笔记主要内容&#xff1a;介绍R语言中绘制箱线图和散点图的方法&#xff0c;以及二者结合展示教程&#xff0c;添加差异比较显著性分析&#xf…