【浅谈设计模式】(15): 命令模式小妖怪的夏天

【浅谈设计模式】(15): 命令模式小妖怪的夏天

首页卡牌对战夏日妖怪录更新时间:2024-06-26

---

theme: nico

---

我正在参加「掘金·启航计划」

# 前言

>⛱ 小猪妖有个梦想,那就是离开浪浪山,出去闯荡,

>

>但是在短篇当中小猪妖并没有走出浪浪山,和我们普通人一样,都走不出自己的浪浪山。

>

>我知道浪浪山的那边还是山,可我还是想去看看。

>

>--《中国奇谭》

![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ac0b5f47c630444290e2fd880f2fa091~tplv-k3u1fbpfcp-zoom-1.image)

# 一、入门

![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/28634e06aed74be5b9859d79fcc981f5~tplv-k3u1fbpfcp-zoom-1.image)

## 1.1 概述

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

命令模式的一个核心就是 "解耦" 。

那是谁发生了耦合呢?

答:请求发起者和请求接收者的耦合。典型的例子就是餐厅点餐,由顾客点好菜单,这个菜单就是"命令",然后 "接收者" 厨师开始制作;倘若没有解耦,那就是由顾客直接跟厨师交代事情。命令模式非常像消息队列,有消息生产者、消费者、以及消息命令。

本文以《小妖怪的夏天》中的场景来理解下命令模式。

>大王想吃唐僧肉,于是开了场项目立项大会,将这个命令分发下去,教头又把命令分发给不同的小弟,对于大王来说,它只需要关心消息发送下去了,而接收到消息的小妖怪们,就开始执行不同的命令,有烧水的、有制作箭头的、有砍菜的~

![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0387e3c8f1fc412ea2a786e87225c95a~tplv-k3u1fbpfcp-zoom-1.image)

命令模式是一种数据驱动的设计模式,将请求命令封装成一个命令对象,由调用者将这个命令对象发给执行者。

## 1.2 结构

![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/de35df4429a54b18b4b72ecc4bf59159~tplv-k3u1fbpfcp-zoom-1.image)

命令模式包含以下主要角色:

- 抽象命令类(Command)角色: 定义命令的接口,声明执行的方法。

- 具体命令(Concrete Command)角色:具体的命令,实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。

- 实现者/接收者(Receiver)角色: 接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。

- 调用者/请求者(Invoker)角色: 要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。

# 二、案例实战

对小妖怪的案例做个代码演示。

实现者角色(无名的小妖怪),也可以定义一个抽象类,继承实现。

```

/**

* 一只无名的小妖怪

* @Author xiaolei

* @Date 2023/2/28 13:19

**/

public class Nobody {

/**

* 执行烧水工作

*/

public void execBoilWater(){

System.out.println("大王让我来烧水!");

}

/**

* 执行制箭工作

*/

public void execMakeArrow(){

System.out.println("大王让我做1000支箭!");

}

}

```

抽象命令接口

```

/**

* 小妖怪抽象命令接口

* @Author xiaolei

* @Date 2023/2/28 13:12

**/

public interface GoblinCommand {

void execute();

}

```

具体命令角色

```

/**

* 烧水具体命令

* 具体命令中需要传入一个具体干活的对象

* @Author xiaolei

* @Date 2023/2/28 13:23

**/

public class BoilWaterComman implements GoblinCommand {

private Nobody nobody;

/**

* 这里的 nobody 也可以抽象出一个抽象类

* @param nobody

*/

public BoilWaterComman(Nobody nobody){

this.nobody = nobody;

}

/**

* 该命令只负责让接收者干烧水的事情

*/

@Override

public void execute() {

nobody.execBoilWater();

}

}

// 制作箭头具体命令

public class MakeArrowCommand implements GoblinCommand{

private Nobody nobody;

/**

* 这里的 nobody 也可以抽象出一个抽象类

* @param nobody

*/

public MakeArrowCommand(Nobody nobody){

this.nobody = nobody;

}

/**

* 该命令只负责让接收者干制箭的事情

*/

@Override

public void execute() {

nobody.execMakeArrow();

}

}

```

调用者角色 (大王)

```

/**

* 大王 : 命令的发起者。

* 注意它是跟命令直接交互的,而命令是跟干活的直接交互的,所以需要传入 命令

* the king of the forest

* 森林之王

* @Author xiaolei

* @Date 2023/2/28 13:28

**/

public class TheKingInvoker {

private GoblinCommand command;

/**

* 根据命令创建调用者

* @param command

*/

public TheKingInvoker(GoblinCommand command){

this.command = command;

}

/**

* 大王开始吩咐命令

*/

public void action(){

command.execute();

}

}

```

客户端测试

```

public class ClientTest {

public static void main(String[] args) {

// 小妖怪上线

Nobody nobody = new Nobody();

BoilWaterComman boilWaterComman = new BoilWaterComman(nobody);

// 大王吩咐执行烧水命令

TheKingInvoker theKingInvoker = new TheKingInvoker(boilWaterComman);

// 开始执行

theKingInvoker.action();

System.out.println("===================================");

MakeArrowCommand makeArrowCommand = new MakeArrowCommand(nobody);

// 大王吩咐执行制箭命令

TheKingInvoker theKingInvoker2 = new TheKingInvoker(makeArrowCommand);

// 开始执行

theKingInvoker2.action();

}

}

```

![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/21c1cf20d49243b79899d0b50e8e31f9~tplv-k3u1fbpfcp-zoom-1.image)

# 三、总结

## 3.1 使用场景

- 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。

- 系统需要在不同的时间指定请求、将请求排队和执行请求。

- 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。

## 3.2 优缺点

**优点:**

- 降低系统的耦合度。命令模式能将调用操作的对象与实现该操作的对象解耦。

- 增加或删除命令非常方便。采用命令模式增加与删除命令不会影响其他类,它满足“开闭原则”,对扩展比较灵活。

- 可以实现宏命令。命令模式可以与组合模式结合,将多个命令装配成一个组合命令,即宏命令。

- 方便实现 Undo 和 Redo 操作。命令模式可以与后面介绍的备忘录模式结合,实现命令的撤销与恢复。

**缺点:**

- 使用命令模式可能会导致某些系统有过多的具体命令类。

- 系统结构更加复杂。

命令模式的入门就到这了,感觉命令模式在业务的使用应该很少,可能在重构的时候会考虑吧,一句话就是以数据驱动来完成调用者与执行者的解耦工作。

我想离开浪浪山,那你要变得更强呀~~

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved