欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

一起学设计模式 - 命令模式

发布时间:2025/7/14 57 豆豆
生活随笔 收集整理的这篇文章主要介绍了 一起学设计模式 - 命令模式 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

命令模式(Command Pattern)属于行为型模式的一种,又称为行动(Action)模式或交易(Transaction)模式。将一个请求封装为一个对象,从而达到用不同的请求对客户进行参数化,对于排队请求或请求日志记录,可以提供命令的撤销和恢复功能。

<!-- more -->

概述

命令模式:对命令的封装,把发送命令和执行命令的责任分割开,分别委派给不同的对象,每一个命令都是一个操作,允许请求方与接收方独立开来,使之请求方不必清楚接收方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。

UML结构图

模式结构

  • Command(抽象命令类): 声明了用于执行请求的的exceute()等方法
  • ConcreteCommand(具体命令类): 抽象命令类的子类,对应具体的接收者对象,将接收者对象的动作绑定其中。在实现execute()方

法时,将调用接收者对象的相关操作(Action)。

  • Invoker(调用者): 调用命令对象执行请求,相关的方法叫做行动方法。
  • Receiver(接收者): 负责具体实施和执行一个请求。任何一个类都可以成为接收者,实施和执行请求的方法叫做行动方法。

案例

博主比较喜欢听歌,这里就以MusicPlayer(音乐播放器)为案例,一般播放器中都有播放(play),跳过(skip),停止(stop)等功能,是一种比较典型的命令模式

UML图如下:

1.定义Command(抽象命令类),只有一个execute()用来执行命令

interface Command {void execute(); }

2.创建不同指令的ConcreteCommand(具体命令类)

class PlayCommand implements Command {private MusicPlayer musicPlayer;public PlayCommand(MusicPlayer musicPlayer) {this.musicPlayer = musicPlayer;}@Overridepublic void execute() {musicPlayer.play();} }class SkipCommand implements Command {private MusicPlayer musicPlayer;public SkipCommand(MusicPlayer musicPlayer) {this.musicPlayer = musicPlayer;}@Overridepublic void execute() {musicPlayer.skip();} }class StopCommand implements Command {private MusicPlayer musicPlayer;public StopCommand(MusicPlayer musicPlayer) {this.musicPlayer = musicPlayer;}@Overridepublic void execute() {musicPlayer.stop();} }

3.MusicInvoker(调用者),接收客户端发送过来的指令

class MusicInvoker {private Command playCommand;private Command skipCommand;private Command stopCommand;public void setPlayCommand(Command playCommand) {this.playCommand = playCommand;}public void setSkipCommand(Command skipCommand) {this.skipCommand = skipCommand;}public void setStopCommand(Command stopCommand) {this.stopCommand = stopCommand;}public void play() {playCommand.execute();}public void skip() {skipCommand.execute();}public void stop() {stopCommand.execute();} }

4.MusicPlayer(接收者),执行接收到的指令

class MusicPlayer {public void play() {System.out.println("播放...");}public void skip() {System.out.println("跳过...");}public void stop() {System.out.println("停止...");} }

5.测试类MusicPlayerClient

public class MusicPlayerClient {public static void main(String[] args) {// 创建 Receiver(接收者)MusicPlayer musicPlayer = new MusicPlayer();// Command(抽象命令类)Command playCommand = new PlayCommand(musicPlayer);Command skipCommand = new SkipCommand(musicPlayer);Command stopCommand = new StopCommand(musicPlayer);// 创建 Invoker(调用者)MusicInvoker invoker = new MusicInvoker();invoker.setPlayCommand(playCommand);invoker.setSkipCommand(skipCommand);invoker.setStopCommand(stopCommand);// 测试invoker.play();invoker.skip();invoker.stop();invoker.play();invoker.stop();} }

6.运行结果

宏命令

宏命令: 又称为组合命令,组合多个命令,它是命令模式和组合模式联用的产物;

假设MusicPlayer(音乐播放器)有一个记录功能,可以把每一个命令记录下来,在需要的时候又可以将历史记录的命令在执行一遍,这就是所谓的宏命令集功能。

UML图如下:

1.定义MacroCommand(宏命令类),继承基础Command(命令类)

interface MacroCommand extends Command {void add(Command command);void remove(Command command); }

2.创建MacroMusicCommand实现MacroCommand

class MacroMusicCommand implements MacroCommand {private static final List<Command> COMMANDS = new ArrayList<>();@Overridepublic void execute() {System.out.println("==========回放开始==========");COMMANDS.forEach(Command::execute);System.out.println("==========回放结束==========");}@Overridepublic void add(Command command) {COMMANDS.add(command);}@Overridepublic void remove(Command command) {COMMANDS.remove(command);} }

3.测试类

public class MusicPlayerClient {public static void main(String[] args) {// 创建 Receiver(接收者)MusicPlayer musicPlayer = new MusicPlayer();// Command(抽象命令类)Command playCommand = new PlayCommand(musicPlayer);Command skipCommand = new SkipCommand(musicPlayer);Command stopCommand = new StopCommand(musicPlayer);// 创建 Invoker(调用者)MacroCommand macroCommand = new MacroMusicCommand();macroCommand.add(playCommand);macroCommand.add(skipCommand);macroCommand.add(stopCommand);// 测试macroCommand.execute();} }

4.运行结果

JDK中应用

我们平时使用的java.lang.Runnable就是命令模式的经典应用

// 命令类 与 具体命令实现类 Runnable runnable = new Runnable() {@Overridepublic void run() {System.out.println("关注 battcn 公众号即可免费领取视频");} }; // Invoker(调用者) 接收命令 Thread thread = new Thread(runnable); // 调用 start 命令 thread.start(); // JDK8 简化写法 new Thread(()->System.out.println("关注 battcn 公众号即可免费领取视频")).start();

总结

优点

  • 将行为调用者和各种行为分隔开,降低程序的耦合,便于程序扩展;
  • 将行为的具体实现封装起来,客户端无需关心行为的具体实现;
  • 为多种行为提供统一的调用入口,便于程序对行为的管理和控制;

缺点

  • 使用命令模式,不论命令简单还是复杂,都需要写一个命令类来封装,滥用命令模式会导致系统出现过多的具体命令类;

适用场景

  • 希望将行为请求者和行为实现者解耦,不直接打交道;
  • 希望分离掉行为请求者一部分的责任,行为请求者只需要将命令发给调用者,不再主动的去让行为实现者产生行为,符合单一职责原则;
  • 希望可以控制执行的命令列表,方便记录,撤销/重做以及事务等功能;
  • 希望可以将请求组合使用,即支持宏命令;

说点什么

全文代码:https://gitee.com/battcn/design-pattern/tree/master/Chapter12/battcn-command

  • 个人QQ:1837307557
  • battcn开源群(适合新手):391619659

微信公众号:battcn(欢迎调戏)

福利

关注公众号:battcn,回复springboot即可获得 <Spring Boot从入门到实战 基础实战系列教程全集> 与 <2017最新spring boot 外卖实战微信公众平台视频教程>

总结

以上是生活随笔为你收集整理的一起学设计模式 - 命令模式的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。