命令模式中介者模式

article/2025/10/20 14:07:55

有情怀,有干货,微信搜索【三太子敖丙】关注这个有一点点东西的程序员。

本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点、资料以及我的系列文章。

最近在跟大家分享设计模式系列的文章有学妹问我,命令模式、策略模式、工厂模式 它们分别有啥区别?看代码的实现上感觉没啥区别呀?

之前已经跟大家分享了策略模式以及工厂模式感兴趣的同学可以再去复习一下,今天我们就先重点分析一下命令模式然后再来看看它们的区别是啥?

往期回顾:

  • 单例模式
  • 工厂模式
  • 流程引擎
  • 建造者模式
  • 原型模式
  • 责任链模式
  • 观察者模式
  • 策略模式
  • 模板方法
  • 迭代器模式
  • 代理模式
  • 对象池&解释器模式

命令模式

定义
  • 提供一个统一的方法来封装命令,通过参数条件来判断选择执行什么命令动作。
  • 允许将每一个命令存储在一个队列中。

整体结构图如下:

结构图中重要角色解释:

  • Command(命令类):定义命令的抽象封装类。
  • ConcreteCommand(具体命令类):对Command类进行实现,说白了就是具体的命令的实际实现类。
  • Receiver(接收者):执行命令关联的操作类。
  • Invoker(调用者):触发命令类,即外部操作事件触发执行。
  • Client(客户端):实例化具体命令对象,及接收者的实际类。

整个结构其实看上去还是比较难理解的,但是既然开始在学设计模式了,那肯定每种设计模式都要有了解,来提升自己的知识面

为了加深理解,我还是举一个好理解的例子:

大家对中国古代君主制度肯定很熟悉。皇帝可以针对手底下服侍的公公让她们可以收取或者发放奏折。那其实这里面我个人感觉就可以体现命令模式。

公公 相当于命令模式的接受者(Receiver),执行皇帝的命令,收取早朝奏折(ConcreteCommand) 还是颁布圣旨(ConcreteCommand)

皇帝 相当于命令模式的调用者(Invoker)

老规矩,例子说完,看看代码吧

// 定义 命令类
public interface Command {// 执行的方法void execute();
}// 定义接收者-公公的角色
public class Receiver {public void Charge(){System.out.println("收取奏折");}public void Issue(){System.out.println("颁布圣旨");}
}//具体命令类one,收取奏折命令
public class ConcreteCommandOne implements Command {// 接受者,这里可以理解为公公private Receiver receiver;public ConcreteCommandOne(Receiver receiver) {this.receiver = receiver;}@Overridepublic void execute() {// 收取奏折receiver.Charge();}
}// 具体命令类two,颁布圣旨
public class ConcreteCommandTwo implements Command {// 接受者,这里可以理解为公公private Receiver receiver;public ConcreteCommandTwo(Receiver receiver) {this.receiver = receiver;}@Overridepublic void execute() {// 颁布圣旨receiver.Issue();}
}// 调用者,皇帝
public class Invoker {private Command command;public Invoker(Command command) {this.command = command;}// 本次需要执行的命令public void action() {command.execute();}
}// 测试demopublic static void main(String[] args) {// 实例化一个公公 接收者Receiver receiver =new Receiver();// 公公 当前能有接收到的几种命令Command commandOne = new ConcreteCommandOne(receiver);Command commandTwo = new ConcreteCommandTwo(receiver);// 皇帝 发号命令 触发执行方法Invoker invoker =new Invoker(commandOne);invoker.action();// result: 收取奏折Invoker invokerTwo =new Invoker(commandTwo);invokerTwo.action();// result:颁布圣旨}

以上就是简单的代码实现了,通过Invoker(皇帝)的选择可以让Receiver(公公)确定去执行什么命令。这其实就是命令模式的一种简单体现。

细心的同学不知道有没有发现一个问题,在定义里面

  • 允许将每一个命令存储在一个队列中。

我们这里是没有体现队列的,其实这个实现也很简单。在main方法中添加一个队列就可以了

    public static void main(String[] args) {// 实例化一个公公 接收者Receiver receiver = new Receiver();// 公公 当前能有接收到的几种命令Command commandOne = new ConcreteCommandOne(receiver);Command commandTwo = new ConcreteCommandTwo(receiver);// 存储命令Queue<Command> queue = new LinkedList<>();queue.add(commandOne);queue.add(commandTwo);// 批量执行for (Command command : queue) {Invoker invoker = new Invoker(command);invoker.action();}}

这里我想给大家做一个扩展点,这也是我之前看到过一种校验写法。

大家在真实的工作中肯定会遇到很多一些接口的校验,怎么去写这个校验逻辑,怎么做到代码的复用、抽象等这其实是一个比较难的问题!

还是大致的来看下结构图吧!!!

demo代码,我也给大家写出来,需要注意的是我们需要实现 ApplicationContextAware 里面的afterPropertiesSet 方法。

// 定义抽象校验方法
public abstract class ValidatePlugin {public abstract void validate();
}
// 抽象规则执行器
public abstract class ValidatePluginExecute {protected abstract List<ValidatePlugin> getValidatePlugins();public void execute() {final List<ValidatePlugin> validatePlugins = getValidatePlugins();if (CollectionUtils.isEmpty(validatePlugins)) {return;}for (ValidatePlugin validatePlugin : validatePlugins) {// 执行校验逻辑,这里大家可以根据自己的实际业务场景改造validatePlugin.validate();}}
}// 具体测试规则
@Component("validatePluginOne")
public class ValidatePluginOne extends  ValidatePlugin {@Overridepublic void validate() {System.out.println("validatePluginOne 规则校验");}
}// 具体执行器,把需要执行的规则添加到 validatePlugins 中
@Component("testValidatePlugin")
public class TestValidatePlugin extends ValidatePluginExecute implements ApplicationContextAware, InitializingBean {protected ApplicationContext applicationContext;private List<ValidatePlugin> validatePlugins;@Overridepublic void afterPropertiesSet() {// 添加规则validatePlugins = Lists.newArrayList();validatePlugins.add((ValidatePlugin) this.applicationContext.getBean("validatePluginOne"));}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}@Overrideprotected List<ValidatePlugin> getValidatePlugins() {return this.validatePlugins;}
}// 测试demopublic static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");TestValidatePlugin testValidatePlugin = (TestValidatePlugin) applicationContext.getBean("testValidatePlugin");testValidatePlugin.execute();}

这个只是一个简单的测试demo,为了让大家有一个思考,设计模式不一定是照搬代码。更多是开拓自己的视野,提升自己解决问题的能力。

针对不同的一些接口,我们只需要在TestValidatePlugin 中添加具体校验规则就可以了,整体的扩展性就变高了,看上去也比较高大上。

所以上面提到的命令模式、策略模式、工厂模式区别是什么呢?

  • 命令模式:属于行为型设计模式,在命令模式中,不同的命令执行过程中会产生不同的目的结果,而且不同的命令是不能替换的。

  • 策略模式 :属于行为型设计模式,在策略模式中,重点在于针对每一种策略执行,解决根据运行时状态从一组策略中选择不同策略的问题

  • 工厂模式:属于创建型设计模式,在工厂模式中,重点在于封装对象的创建过程,这里的对象没有任何业务场景的限定,可以是策略,但也可以是其他东西

所以针对设计模式,其实我理解的还是只说明了一个问题,不同的设计模式都是为了针对处理不同的场景,不同业务场景有不同的写法。

中介者模式

中介者模式,看这个名字也能理解出来,定一个中间结构来方便管理下游组织。

那么什么是中介模式呢?

在GoF 中的《设计模式》中解释为:中介模式定义了一个单独的(中介)对象,来封装一组对象之间的交互。将这组对象之间的交互委派给与中介对象交互,来避免对象之间的直接交互。

再来看看这个结构图吧:

  • Mediator(抽象中介者):用来定义参与者与中介者之间的交互方式

  • ConcreteMediator(具体中介者):实现中介者定义的操作,即就是实现交互方式。

  • Colleague(抽象同事角色):抽象类或者接口,主要用来定义参与者如何进行交互。

  • ConcreteColleague(具有同事角色):很简单,就是具体的实现Colleague中的方法。

    以上结构定义来自设计模式之美

看这个结构图理解出来,其实是跟之前为大家写的一篇观察者模式有点相同的,感兴趣的同学可以再去复习一下。

老规矩,还是具体举例代码实现一下

高铁系统大家应该清楚有一个调度中心,用来控制每一辆高铁的进站顺序,如果没有这个调度中心,当同时有三量高铁都即将进站时,那他们就需要两两相护沟通。假设有其中的一辆动车没有沟通到,那就将发生不可估量的错误,所以就需要通过这个调度中心来处理这个通信逻辑,同时来管理当前有多少车辆等待进站等。

// 抽象参与者, 也可以使用abstract 写法
public interface Colleague {// 沟通消息void message();
}
// 抽象中介者
public interface Mediator {// 定义处理逻辑void doEvent(Colleague colleague);
}// 具体参与者
@Component
public class MotorCarOneColleague implements Colleague {@Overridepublic void message() {// 模拟处理业务逻辑System.out.println("高铁一号收到消息!!!");}
}
@Component
public class MotorCarTwoColleague implements Colleague {@Overridepublic void message() {System.out.println("高铁二号收到消息!!!");}
}
@Component
public class MotorCarThreeColleague implements Colleague {@Overridepublic void message() {System.out.println("高铁三号收到消息!!!");}
}// 具体中介者
@Component
public class DispatchCenter implements Mediator {// 管理有哪些参与者@Autowiredprivate List<Colleague> colleagues;@Overridepublic void doEvent(Colleague colleague) {for(Colleague colleague1 :colleagues){if(colleague1==colleague){// 如果是本身高铁信息,可以处理其他的业务逻辑// doSomeThing();continue;}// 通知其他参与colleague1.message();}}
}// 测试demo
public static void main(String[] args) {// 初始化spring容器ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");// 获取中介者,调度中心DispatchCenter dispatchCenter = (DispatchCenter) applicationContext.getBean("dispatchCenter");// 一号高铁 发送消息出去MotorCarOneColleague motorCarOneColleague =  (MotorCarOneColleague) applicationContext.getBean("motorCarOneColleague");// 通过调度中心沟通信息dispatchCenter.doEvent(motorCarOneColleague);// result:高铁三号收到消息!!!//         高铁二号收到消息!!!// 二号高铁 发送消息出去MotorCarTwoColleague  motorCarTwoColleague = (MotorCarTwoColleague)applicationContext.getBean("motorCarTwoColleague");dispatchCenter.doEvent(motorCarTwoColleague);// result:高铁一号收到消息!!!//         高铁三号收到消息!!!}

中介者模式demo代码就算完成了,通过这个demo大家应该能发现,中介者还是很好理解的。

但是中介者的应用场景还是比较少见的,针对一些类依赖严重,形成的类似网状结构,改成一个类似与蒲公英一样结构,由中间向外扩散,来达到解耦合的效果。

更多在一个UI界面控件里面比较常见,当然在Java里面java.util.Timer 也可以理解为中介者模式,因为它能控制内部线程如何去运行比如多久运行一次等。

上面提到中介者和观察者模式很像,通过demo代码大家也能发现这一点

观察者模式中观察者和被观察者我们基本时固定的,而中介者模式中,观察者和被观察者时不固定的,而且中介者可能会最后变成一个庞大的原始类。

总结

命令模式:虽然不怎么常见,但是我们还是要区分它与工厂模式以及策略模式的区别是啥,应用场景是啥,能给我们带来什么思考。

比如我最后的那个例子,命令模式可以实现命令的存储,本质是将命令维护在一个队列中,那么在我们的业务代码中 我们为什么不能也通过一个数组来维护一些接口校验依赖,里面存放需要校验的bean实例。来提高代码的复用性以及扩展性。

中介模式:整体来说这个更加不怎么应用,虽然能起到对象的解耦合,但是也有副作用,而且在我们的真实业务场景中也很少会遇到这样的场景,了解一下实现原理即可,至于与观察者的区别,上面也有讲到,更多我们可能是已经在使用一些中间件消息队列去处理了。

我是敖丙,你知道的越多,你不知道的越多,我们下期见!!!


敖丙把自己的面试文章整理成了一本电子书,共 1630页!

干货满满,字字精髓。目录如下,还有我复习时总结的面试题以及简历模板,现在免费送给大家。

链接:https://pan.baidu.com/s/1ZQEKJBgtYle3v-1LimcSwg 密码:wjk6

我是敖丙,你知道的越多,你不知道的越多,感谢各位人才的:点赞收藏评论,我们下期见!


文章持续更新,可以微信搜一搜「 三太子敖丙 」第一时间阅读,回复【资料】有我准备的一线大厂面试资料和简历模板,本文 GitHub https://github.com/JavaFamily 已经收录,有大厂面试完整考点,欢迎Star。


http://chatgpt.dhexx.cn/article/mjtx4716.shtml

相关文章

Linux 三种命令模式

vim :文本编辑器 vim的三种模式&#xff1a;命令模式、输入模式、底线命令模式 命令模式:即用户刚刚启动的Vim模式 常用命令 i 切换到输入模式&#xff0c;输入字符。x 删除当前光标所在出的字符。: 切换到底线命令模式&#xff0c;一在最底行输入命令。 输入模式:在命令模…

【源码分析设计模式 13】命令模式

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

C# 命令模式

一、命令模式&#xff1a; 将一个请求封装为一个对象&#xff0c;从而使你可用不同的请求对客户进行参数化&#xff1b;对请求排队或记录请求日志&#xff0c;以及支持可撤销的操作。 ——《设计模式》 二、模式结构&#xff1a; Command&#xff1a; 定义命令的接口&#xff…

命令模式(Command模式)详解

在软件开发系统中&#xff0c;常常出现“方法的请求者”与“方法的实现者”之间存在紧密的耦合关系。这不利于软件功能的扩展与维护。例如&#xff0c;想对行为进行“撤销、重做、记录”等处理都很不方便&#xff0c;因此“如何将方法的请求者与方法的实现者解耦&#xff1f;”…

交换机基本命令模式

交换机基本命令模式 对于思科交换机来说&#xff0c;主要有2种配置途径&#xff1a; 其一&#xff0c;使用交换机自带的Console线缆连接到计算机的COM口&#xff0c;然后利用计算机的超级终端软件直接配置&#xff0c;首次配置通常使用这种方式&#xff1b; 其二&#xff0c;通…

Java设计模式及应用场景之《命令模式》

文章目录 一、命令模式定义二、命令模式的结构和说明三、命令模式示例四、命令模式扩展 -- 宏命令示例五、命令模式扩展 -- 可撤销和恢复操作示例1、反操作式&#xff08;补偿式&#xff09;2、存储恢复式 六、命令模式扩展 -- 队列请求七、命令模式扩展 -- 日志请求八、命令模…

【每天一个java设计模式(十五)】 - 命令模式

命令模式是一种数据驱动的设计模式&#xff0c;它属于行为型模式。请求以命令的形式包裹在对象中&#xff0c;并传给调用对象。调用对象寻找可以处理该命令的合适的对象&#xff0c;并把该命令传给相应的对象&#xff0c;该对象执行命令。 命令模式也就是一个用户发送请求&…

码农小汪-设计模式之-命令模式

大话设计模式的例子讲的非常的好&#xff0c;理解起来也方便&#xff01;有时候忘了。想到这些特殊的例子感觉就是特别爽。 烤羊肉串带来的思考&#xff01; 路边摊羊肉串&#xff1a; 老板&#xff0c;我这里排的比较先啊&#xff0c;我最先给钱。老板这个没有熟啊。我的是…

命令模式(行为型)

一、什么是命令式 命令(Command)模式又叫作动作(Action)模式或事务(Transaction)模式&#xff0c;是一种对象的行为模式。将一个请求封装为一个对象&#xff0c;从而使你可用不同的请求对客户进行参数化&#xff1b;对请求排队或记录请求日志&#xff0c;以及支持可撤消的操作…

命令模式---电视机遥控器

电视机是请求的接收者&#xff0c;遥控器是请求的发送者&#xff0c;遥控器上有一些按钮&#xff0c;不同的按钮对应电视机的不同操作。抽象命令角色由一个命令接口来扮演&#xff0c;有三个具体的命令类实现了抽象命令接口&#xff0c;这三个具体命令类分别代表三种操作&#…

C++设计模式-命令模式

目录 基本概念 代码与实例 基本概念 命令模式&#xff08;Command&#xff09;&#xff0c;将一个请求封装为对象&#xff0c;从而使你看用不同的请求对客户端进行参数化&#xff1b;对请求排队或记录请求日志&#xff0c;以及支持可撤销操作。 命令模式的作用&#xff1a; …

设计模式---命令模式

命令模式 命令模式的定义 ​ 命令模式是一个高内聚的模式&#xff0c;其定义为&#xff1a;Encapsulate a request as an object,thereby letting you parameterize clients with different requests,queue or log requests,and support undoable operations.&#xff08;将一…

【设计模式】命令模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )

文章目录 一、命令模式简介二、命令模式 适用场景三、命令模式 优缺点四、命令模式 与 备忘录模式五、命令模式 代码示例1、命令接口2、发布命令类3、关闭命令类4、游戏类5、命令执行者类6、测试类 一、命令模式简介 命令模式 : 将 不同的请求 封装成 不同的请求对象 , 以便 使…

设计模式(16)命令模式

**定义&#xff1a;**将一个请求封装成一个对象&#xff0c;从而让你使用不同的请求把客户端参数化&#xff0c;对请求排队或者记录请求日志&#xff0c;可以提供命令的撤销和恢复功能。 **类型&#xff1a;**行为类模式 类图&#xff1a; 命令模式的结构 ​ 顾名思义&#…

什么是命令模式?

一、命令模式的定义 命令是对命令的封装&#xff0c;每一个命令都是一个操作&#xff0c;请求方发出请求&#xff0c;接收方接收请求&#xff0c;并执行操作。命令模式解耦了请求方和接收方&#xff0c;命令模式属于行为型模式 二、命令模式的uml图和通用写法 uml 通用写法 …

设计模式之命令模式详解

1 概述 日常生活中&#xff0c;我们出去吃饭都会遇到下面的场景。我们可以将女招待理解成一个请求的发送者&#xff0c;用户通过它来发送一个“点餐”请求&#xff0c;而厨师是“点餐”请求的最终接收者和处理者&#xff0c;在图中&#xff0c;顾客和厨师之间并不存在直接耦合…

命令模式

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

Java设计模式——命令模式

文章目录 命令模式 命令模式 命令模式很好理解&#xff0c;举个例子&#xff0c;司令员下令让士兵去干件事情&#xff0c;从整个事情的角度来考虑&#xff0c;司令员的作用是&#xff0c;发出口令&#xff0c;口令经过传递&#xff0c;传到了士兵耳朵里&#xff0c;士兵去执行…

如何设置IPv4和IPv6报文的DSCP值——网络测试仪实操

一、操作说明 在QoS测试中&#xff0c;经常要设置不同优先级的报文&#xff0c;来验证被测设备对于优先级的调度。所以&#xff0c;我们就要了解如何设置IPv6和IPv6报文中的DSCP&#xff08;大部分使用DSCP值&#xff0c;也会用到TOS值&#xff09; 这里我们使用测试接交换机&…

DSCP vs IPv4 Tos

首先看IPv4包头如下 其中&#xff0c;Qos用到的是Tos定义有下面两种&#xff1a; 老的IPv4 TOS Byte定义和值 新的DSCP定义和值 DSCP值 DSCP ValueMeaningDrop ProbabilityEquivalent IP Precedence Value101 110 (46)High Priority Expedited Forwarding (EF)N/A101 – …