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

文章目录

  • 引言
  • 命令模式简介
    • 定义与用途
    • 实现方式
  • 使用场景
  • 优势与劣势
  • 在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;}@Overridepublic void execute() {abcStock.buy();}
}public class SellStock implements Order {private Stock abcStock;public SellStock(Stock abcStock){this.abcStock = abcStock;}@Overridepublic 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.mzph.cn/news/238300.shtml

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

相关文章

flutter开发实战-设置bottomNavigationBar中间按钮悬浮效果

flutter开发实战-设置bottomNavigationBar中间按钮悬浮的效果 在使用tabbar时候&#xff0c;可以使用bottomNavigationBar来设置中间凸起的按钮&#xff0c;如下 一、效果图 中间按钮凸起的效果图如下 二、实现代码 我们使用BottomAppBar 一个容器&#xff0c;通常与[Sscaf…

2023年PMP证书的含金量有多高?对于企业来说有多大的价值?

PMP含金量更多的是“敲门砖”作用&#xff0c;公司招聘的门槛 当然现在PMP管理模式也很热门&#xff0c;各大企业都有引进改良应用在公司的项目上&#xff0c;之前在校友群里面大家在讨论PMP 的作用也有说到这一点&#xff0c;给大家看看吧。 至于为什么PMP认证从国外引进大陆…

⭐Unity 读取本地图片再区域裁剪

现在需求是将本地的图片读取之后再区域截图成新的图片 话不多说直接上代码 using UnityEngine; using System.IO;public class LocalRegionCapture : MonoBehaviour {public string fullScreenImagePath "Assets/SavedImages/fullScreenScreenshot.png";public str…

【PyQt学习篇 · ⑭】:QTableView的使用

文章目录 QTableView的使用示例 QTableView的使用 QTableView 是 PyQt 中用于显示表格数据的窗口部件&#xff0c;它提供了一个灵活的方式来显示和编辑数据。下面是一些关于 QTableView 的使用的具体信息&#xff1a; 创建 QTableView 对象&#xff1a; from PyQt5.QtWidgets …

Mac 生成Android签名证书 .keystore文件

工具下载地址 https://www.oracle.com/java/technologies/downloads/#jdk21-mac1. 找到安装jdk的路径&#xff0c;并进入bin目录下 1.1 查找JDK命令 /usr/libexec/java_home -v结果为: java_home: option requires an argument -- v /Library/Java/JavaVirtualMachines/jdk…

python/C 生成beta分布的随机数

python/C 生成beta分布的随机数 文章目录 python/C 生成beta分布的随机数前言一、beta分布理论知识二、python 生成服从beta分布的随机数三、C语言生成服从beta分布的随机数 前言 想把一个算法用C语言实现&#xff0c;其中涉及到了beta分布取随机数&#xff0c;记录一下结果 一…

雀巢困在业绩和质量里

撰稿|行星 来源|贝多财经 雀巢集团CEO马克施奈德曾在2023年中报中表示&#xff0c;后疫情时代居家消费已恢复常态&#xff0c;从而消除了制约雀巢部分品类增长的阻碍。 但就雀巢前三季度财报而言&#xff0c;该公司在全球及大中华区的销售额均有所下降&#xff0c;有机增长主…

如何使用Java的GeoTools地理库计算WGS84坐标下的两个经纬度之间得距离

介绍 本章讲解如何使用Java的GeoTools地理库计算基于WGS84坐标的两点之间的距离。适用于后台服务的距离计算。 GeoTools介绍 GeoTools是开源的Java地理信息计算库。GeoServer地图引擎就是基于GeoTools库构建得地图服务,可以说非常强大。 官网地址:https://docs.geotools.o…

Baumer工业相机堡盟工业相机如何通过BGAPI SDK实现Raw格式的图像保存(C#)

Baumer工业相机堡盟工业相机如何通过BGAPI SDK实现Raw格式的图像保存&#xff08;C#&#xff09; Baumer工业相机Baumer工业相机通过SDK实现Raw格式的图像保存的技术背景通过SDK获取相机信息的代码分析Baumer工业相机回调函数里保存原始图像数据Baumer保存Raw图像格式重要核心代…

TikTok真题第1天 | 666.路径和IV、 207.课程安排、210.课程安排

666.路径和IV 题目链接&#xff1a;666.路径和IV 解法&#xff1a; 参考这篇题解&#xff1a;【LeetCode - 666】路径和 IV_力扣666路径总和4-CSDN博客 关键点在于&#xff1a; &#xff08;1&#xff09;使用map来存node&#xff1a;key 为整数的前两位&#xff0c;value…

龙芯loongarch64服务器编译安装paddlepaddle

前言 PaddlePaddle (Parallel Distributed Deep Learning,中文名飞桨)是百度公司推出的开源,易学习,易使用的分布式深度学习平台,现阶段各行各业均追求国产化,软件行业也一样,所有需要在龙芯服务器上编译安装paddlepaddle。 官方教程 官方教程里面很多没有讲解到,安…

SQL编写规范及性能排查一些方法

SQL 语句编写规范 避免使用select *&#xff0c;对于宽表来说&#xff0c;这是灾难&#xff1b;严禁不加任何where条件读取数据&#xff1b;MySQL中的text类型字段独立存储&#xff0c;数据量少的表除外&#xff1a;Where条件中的过滤条件字段上严禁使用任何函数&#xff0c;包…

ubuntu 搭建本地私有pip源

# 搭建本地私有pip源 pip install pip2pi# 创建目录 mkdir /data/work/PyPip/ mkdir /data/work/PyPip/packages cd /data/work/PyPip/# 创建需要从外网源同步的package touch requirements_roop.txt# 批量同步 pip2tgz /data/work/PyPip/packages -r requirements_roop.txt# 同…

【JS】按照a>b>c>d>e>f的优先级,将a,b,c,d,e,f元素进行筛选,选出三个不为空字符的元素进行字符拼接

设计思路&#xff1a; 1、定义一个数组&#xff0c;把元素按照优先级进行排序&#xff1b; 2、 使用 filter() 方法过滤掉空字符串元素&#xff0c;得到一个新的数组; 3、在排序函数中&#xff0c;循环数组&#xff0c;使用 indexOf() 方法获取元素 a 和 b 在数组中的索引&a…

描述一个bug及定义bug的级别

&#xff08;一&#xff09;描述一个bug 描述一个bug&#xff0c;需要以下几个因素&#xff1a; 故障标题、故障发现的版本、故障类别&#xff08;功能/兼容/界面&#xff09;、故障优先级、故障描述&#xff08;测试环境、测试步骤、预期结果、实际结果&#xff09;。 举个例…

spring的SPI机制之使用SpringFactoriesLoader加载服务实现

SpringFactoriesLoader提供了一种工厂方式供spring容器来加载特定的服务。像java的SPI一样&#xff0c;约定固定的配置文件和格式&#xff0c;使用SpringFactoriesLoader进行按需加载。只不过SpringFactoriesLoader读取的配置文件位置 “META-INF/spring.factories”。这个文件…

C++的作用域详细解读

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、作用域是什么&#xff1f;二、作用域类别1.全局作用域&#xff08;global scope&#xff09;2.名字空间作用域&#xff08;namespace scope&#xff09;3.局…

使用Exchanger线程之间交换数据

public class ExchangeThread {static class Producer implements Runnable{//生产者、消费者交换的数据结构private List<String> buffer;//步生产者和消费者的交换对象private Exchanger<List<String>> exchanger;Producer(List<String> buffer,Exch…

MySQL,使用Union组合查询

1、基本使用 Union可将多条select语句组合成一个结果集&#xff0c;常见的使用场景有2种&#xff1a; 在单个查询中&#xff0c;从不同的表返回类似结构的数据&#xff1b;对单个表执行多个查询&#xff0c;按单个查询返回数据。 例&#xff1a;检索出所有价格<50的产品&…

批发订货系统小程序怎么推广 四个方案高效获客

微信小程序基于强社交属性&#xff0c;天然自带引流特性&#xff0c;但毕竟小程序也只是一个工具&#xff0c;想要快速获客&#xff0c;还是需要商家主动采取一些措施的。下面分享是个方法&#xff0c;尤其是最后一个&#xff0c;是十分凑效的。大家点个关注点个赞&#xff0c;…