将命令和实际执行者分离,对外提供统一表现
命令模式
概述
将命令封装成对象中,具有以下作用:
- 使用命令来参数化其它对象
- 将命令放入队列中进行排队
- 将命令的操作记录到日志中
- 支持可撤销的操作
类图
- Command:命令
- Receiver:命令接收者,也就是命令真正的执行者
- Invoker:通过它来调用命令
- Client:可以设置命令与命令的接收者
场景模拟:
顾客点菜,小二记下菜,点完之后小二通知各种菜系的厨师做菜
这里的小二就是 Invoker,顾客就是 Client,菜系就是 Command,厨师就是 Receiver
具体实现
不使用命令模式实现
后续如果添加菜品,用 if 不好维护
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public class XiaoEr {
private final Logger logger = LoggerFactory.getLogger(XiaoEr.class);
private final Map<Integer, String> cuisineMap = new ConcurrentHashMap<>();
public void order(int cuisine) { if (1 == cuisine) { cuisineMap.put(1, "广东厨师,烹饪鲁菜,宫廷最大菜系,以孔府风味为龙头"); }
if (2 == cuisine) { cuisineMap.put(2, "江苏厨师,烹饪苏菜,宫廷第二大菜系,古今国宴上最受人欢迎的菜系。"); } }
public void placeOrder() { Gson gson = new Gson(); logger.info("菜单:{}", gson.toJson(cuisineMap)); }
public static void main(String[] args) { XiaoEr xiaoEr = new XiaoEr(); xiaoEr.order(1); xiaoEr.order(2);
xiaoEr.placeOrder(); } }
|
使用命令模式
维护一个菜系( ICuisine )接口,还有一个厨师( ICook )接口,菜系中调用厨师做饭;
ICuisine
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
public interface ICuisine {
void cook(); }
|
GuangDoneCuisine
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
public class GuangDoneCuisine implements ICuisine {
private final ICook cook;
public GuangDoneCuisine(ICook cook) { this.cook = cook; }
@Override public void cook() { this.cook.doCooking(); } }
|
JiangSuCuisine
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
public class JiangSuCuisine implements ICuisine {
private final ICook cook;
public JiangSuCuisine(ICook cook) { this.cook = cook; }
@Override public void cook() { this.cook.doCooking(); } }
|
厨师
1 2 3 4 5 6 7
| public interface ICook {
void doCooking(); }
|
广东厨师
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
public class GuangDongCook implements ICook {
private final Logger logger = LoggerFactory.getLogger(GuangDongCook.class);
@Override public void doCooking() { logger.info("广东厨师,烹饪鲁菜,宫廷最大菜系,以孔府风味为龙头"); } }
|
江苏厨师
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
public class JiangSuCook implements ICook {
private final Logger logger = LoggerFactory.getLogger(JiangSuCook.class);
@Override public void doCooking() { logger.info("江苏厨师,烹饪苏菜,宫廷第二大菜系,古今国宴上最受人欢迎的菜系。"); } }
|
小二,向厨师下达命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
public class XiaoEr {
private final Logger logger = LoggerFactory.getLogger(XiaoEr.class);
private final List<ICuisine> cuisineList = new ArrayList<>();
public void order(ICuisine cuisine) { cuisineList.add(cuisine); }
public synchronized void placeOrder() { for (ICuisine cuisine : cuisineList) { cuisine.cook(); } cuisineList.clear(); } }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class MainTest {
public static void main(String[] args) { GuangDoneCuisine guangDoneCuisine = new GuangDoneCuisine(new GuangDongCook()); JiangSuCuisine jiangSuCuisine = new JiangSuCuisine(new JiangSuCook());
XiaoEr xiaoEr = new XiaoEr(); xiaoEr.order(guangDoneCuisine); xiaoEr.order(jiangSuCuisine);
xiaoEr.placeOrder(); } }
|
输出:
1 2
| 22:23:04.644 [main] INFO icu.sunnyc.cook.impl.GuangDongCook - 广东厨师,烹饪鲁菜,宫廷最大菜系,以孔府风味为龙头 22:23:04.650 [main] INFO icu.sunnyc.cook.impl.JiangSuCook - 江苏厨师,烹饪苏菜,宫廷第二大菜系,古今国宴上最受人欢迎的菜系。
|
调用时序图
可以看到,顾客 new 了俩菜,也就是 new 了俩命令对象(ConcreteCommand),将对象以参数形式传入小二,小二(Invoker)接收到,调用 Command,然后实际的厨师(receiver)开始做菜了。