内容摘自:https://bugstack.cn/md/develop/design-pattern/2020-06-21-重学 Java 设计模式《实战命令模式》.html#重学-java-设计模式-实战命令模式「模拟高档餐厅八大菜系-小二点单厨师烹饪场景」
命令模式在我们通常的互联网开发中相对来说用的比较少,但这样的模式在我们的日常中却经常使用到,那就是Ctrl+C
、Ctrl+V
。当然如果你开发过一些桌面应用,也会感受到这样设计模式的应用场景。从这样的模式感受上,可以想到这是把逻辑实现与操作请求进行分离,降低耦合方便扩展。
命令模式是行为模式中的一种,以数据驱动的方式将命令对象
,可以使用构造函数的方式传递给调用者。调用者再提供相应的实现为命令执行提供操作方法。可能会感觉这部分有一些饶,可以通过对代码的实现进行理解,在通过实操来熟练。
在这个设计模式的实现过程中有如下几个比较重要的点;
在这个案例中我们模拟在餐厅中点餐交给厨师烹饪的场景
命令场景的核心的逻辑是调用方与不需要去关心具体的逻辑实现,在这个场景中也就是点餐人员只需要把需要点的各种菜系交个小二
就可以,小二再把各项菜品交给各个厨师进行烹饪。也就是点餐人员不需要跟各个厨师交流,只需要在统一的环境里下达命令就可以。
在这个场景中可以看到有不同的菜品;山东(鲁菜)、四川(川菜)、江苏(苏菜)、广东(粤菜)、福建(闽菜)、浙江(浙菜)、湖南(湘菜),每种菜品都会有不同的厨师进行烹饪。而客户并不会去关心具体是谁烹饪,厨师也不会去关心谁点的餐。客户只关心早点上菜,厨师只关心还有多少个菜要做。而这中间的衔接的过程,由小二完成。
那么在这样的一个模拟场景下,可以先思考哪部分是命令模式的拆解,哪部分是命令的调用者以及命令的实现逻辑。
接下来使用命令模式来进行代码优化,也算是一次很小的重构。
命令模式可以将上述的模式拆解三层大块,命令、命令实现者、命令的调用者,当有新的菜品或者厨师扩充时候就可以在指定的类结构下进行实现添加即可,外部的调用也会非常的容易扩展。
itstack-demo-design-14-02
└── src
├── main
│ └── java
│ └── org.itstack.demo.design
│ ├── cook
│ │ ├── impl
│ │ │ ├── GuangDongCook.java
│ │ │ ├── JiangSuCook.java
│ │ │ ├── ShanDongCook.java
│ │ │ └── SiChuanCook.java
│ │ └── ICook.java
│ ├── cuisine
│ │ ├── impl
│ │ │ ├── GuangDoneCuisine.java
│ │ │ ├── JiangSuCuisine.java
│ │ │ ├── ShanDongCuisine.java
│ │ │ └── SiChuanCuisine.java
│ │ └── ICuisine.java
│ └── XiaoEr.java
└── test
└── java
└── org.itstack.demo.test
└── ApiTest.java
命令模式模型结构
/**
* 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
* 公众号:bugstack虫洞栈
* Create by 小傅哥(fustack) @2020
*
* 菜系
* 01、山东(鲁菜)——宫廷最大菜系,以孔府风味为龙头。
* 02、四川(川菜)——中国最有特色的菜系,也是民间最大菜系。
* 03、江苏(苏菜)——宫廷第二大菜系,古今国宴上最受人欢迎的菜系。
* 04、广东(粤菜)——国内民间第二大菜系,国外最有影响力的中国菜系,可以代表中国。
* 05、福建(闽菜)——客家菜的代表菜系。
* 06、浙江(浙菜)——中国最古老的菜系之一,宫廷第三大菜系。
* 07、湖南(湘菜)——民间第三大菜系。
* 08、安徽(徽菜)——徽州文化的典型代表。
*/
public interface ICuisine {
void cook(); // 烹调、制作
}
广东(粤菜)
public class GuangDoneCuisine implements ICuisine {
private ICook cook;
public GuangDoneCuisine(ICook cook) {
this.cook = cook;
}
public void cook() {
cook.doCooking();
}
}
江苏(苏菜)
public class JiangSuCuisine implements ICuisine {
private ICook cook;
public JiangSuCuisine(ICook cook) {
this.cook = cook;
}
public void cook() {
cook.doCooking();
}
}
山东(鲁菜)
public class ShanDongCuisine implements ICuisine {
private ICook cook;
public ShanDongCuisine(ICook cook) {
this.cook = cook;
}
public void cook() {
cook.doCooking();
}
}
四川(川菜)
public class SiChuanCuisine implements ICuisine {
private ICook cook;
public SiChuanCuisine(ICook cook) {
this.cook = cook;
}
public void cook() {
cook.doCooking();
}
}
ICook
),并通过这个类提供的方法进行操作命令(烹饪菜品)cook.doCooking()
。public interface ICook {
void doCooking();
}
粤菜,厨师
public class GuangDongCook implements ICook {
private Logger logger = LoggerFactory.getLogger(ICook.class);
public void doCooking() {
logger.info("广东厨师,烹饪鲁菜,宫廷最大菜系,以孔府风味为龙头");
}
}
苏菜,厨师
public class JiangSuCook implements ICook {
private Logger logger = LoggerFactory.getLogger(ICook.class);
public void doCooking() {
logger.info("江苏厨师,烹饪苏菜,宫廷第二大菜系,古今国宴上最受人欢迎的菜系。");
}
}
鲁菜,厨师
public class ShanDongCook implements ICook {
private Logger logger = LoggerFactory.getLogger(ICook.class);
public void doCooking() {
logger.info("山东厨师,烹饪鲁菜,宫廷最大菜系,以孔府风味为龙头");
}
}
苏菜,厨师
public class SiChuanCook implements ICook {
private Logger logger = LoggerFactory.getLogger(ICook.class);
public void doCooking() {
logger.info("四川厨师,烹饪川菜,中国最有特色的菜系,也是民间最大菜系。");
}
}
public class XiaoEr {
private Logger logger = LoggerFactory.getLogger(XiaoEr.class);
private List<ICuisine> cuisineList = new ArrayList<ICuisine>();
public void order(ICuisine cuisine) {
cuisineList.add(cuisine);
}
public synchronized void placeOrder() {
for (ICuisine cuisine : cuisineList) {
cuisine.cook();
}
cuisineList.clear();
}
}
@Test
public void test(){
// 菜系 + 厨师;广东(粤菜)、江苏(苏菜)、山东(鲁菜)、四川(川菜)
ICuisine guangDoneCuisine = new GuangDoneCuisine(new GuangDongCook());
JiangSuCuisine jiangSuCuisine = new JiangSuCuisine(new JiangSuCook());
ShanDongCuisine shanDongCuisine = new ShanDongCuisine(new ShanDongCook());
SiChuanCuisine siChuanCuisine = new SiChuanCuisine(new SiChuanCook());
// 点单
XiaoEr xiaoEr = new XiaoEr();
xiaoEr.order(guangDoneCuisine);
xiaoEr.order(jiangSuCuisine);
xiaoEr.order(shanDongCuisine);
xiaoEr.order(siChuanCuisine);
// 下单
xiaoEr.placeOrder();
}
菜品
与厨师
的组合;new GuangDoneCuisine(new GuangDongCook());
,每一个具体的命令都拥有一个对应的实现类,可以进行组合。xiaoEr.order(guangDoneCuisine);
,这里分别添加了四种菜品,给小二。22:12:13.056 [main] INFO org.itstack.demo.design.cook.ICook - 广东厨师,烹饪鲁菜,宫廷最大菜系,以孔府风味为龙头
22:12:13.059 [main] INFO org.itstack.demo.design.cook.ICook - 江苏厨师,烹饪苏菜,宫廷第二大菜系,古今国宴上最受人欢迎的菜系。
22:12:13.059 [main] INFO org.itstack.demo.design.cook.ICook - 山东厨师,烹饪鲁菜,宫廷最大菜系,以孔府风味为龙头
22:12:13.059 [main] INFO org.itstack.demo.design.cook.ICook - 四川厨师,烹饪川菜,中国最有特色的菜系,也是民间最大菜系。
Process finished with exit code 0