做sorry动图的网站,网店美工主要负责哪些工作,浏览器网页版在线,开发公司前期部门自查自纠报告重学 Java 设计模式#xff1a;实战命令模式「模拟高档餐厅八大菜系#xff0c;小二点单厨师烹饪场景」
一、前言
持之以恒的重要性
初学编程往往都很懵#xff0c;几乎在学习的过程中会遇到各种各样的问题#xff0c;哪怕别人那运行好好的代码#xff0c;但你照着写完…重学 Java 设计模式实战命令模式「模拟高档餐厅八大菜系小二点单厨师烹饪场景」
一、前言
持之以恒的重要性
初学编程往往都很懵几乎在学习的过程中会遇到各种各样的问题哪怕别人那运行好好的代码但你照着写完就报错。但好在你坚持住了否则你可能看不到这篇文章。时间和成长就是相互关联着你在哪条路上坚持走的久就能看见那条的终点有多美但如果你浪费了一次又一次努力的机会那么你也会同样错过很多机遇因为你的路换了。坚持学习、努力成长持以恒的付出一定会有所收获。
学习方法的重要性
不会学习往往会耽误很多时间又没有可观的收成。但不会学习有时候是因为懒造成的尤其是学习视频、书籍资料、技术文档等如果只是看了却不是实际操作验证那么真的很难把别人的知识让自己吸收即使是当时感觉会了也很快就会忘记。时而也经常会有人找到你说“这个我不知道你先告诉我过后我就学。”但过后你学了吗
你愿意为一个知识盲区付出多长时间
你心里时而会蹦出这样的词吗太难了我不会、找个人帮一下吧、放弃了放弃了其实谁都可能遇到很不好解决的问题也是可以去问去咨询的。但如果在这之前你没有在自己的大脑中反复的寻找答案那么你的大脑中就不会形成一个凸点的知识树缺少了这个学习过程也就缺少了查阅各种资料给自己大脑填充知识的机会哪怕是问到了答案最终也会因时间流逝而忘记。
二、开发环境
JDK 1.8Idea Maven涉及工程三个可以通过关注公众号bugstack虫洞栈回复源码下载获取(打开获取的链接找到序号18)
工程描述itstack-demo-design-14-01使用一坨代码实现业务需求itstack-demo-design-14-02通过设计模式优化代码结构增加扩展性和维护性
三、命令模式介绍 图片来自https://refactoringguru.cn/design-patterns/command
命令模式在我们通常的互联网开发中相对来说用的比较少但这样的模式在我们的日常中却经常使用到那就是CtrlC、CtrlV。当然如果你开发过一些桌面应用也会感受到这样设计模式的应用场景。从这样的模式感受上可以想到这是把逻辑实现与操作请求进行分离降低耦合方便扩展。
命令模式是行为模式中的一种以数据驱动的方式将命令对象可以使用构造函数的方式传递给调用者。调用者再提供相应的实现为命令执行提供操作方法。可能会感觉这部分有一些饶可以通过对代码的实现进行理解在通过实操来熟练。
在这个设计模式的实现过程中有如下几个比较重要的点
抽象命令类声明执行命令的接口和方法具体的命令实现类接口类的具体实现可以是一组相似的行为逻辑实现者也就是为命令做实现的具体实现类调用者处理命令、实现的具体操作者负责对外提供命令服务
四、案例场景模拟 在这个案例中我们模拟在餐厅中点餐交给厨师烹饪的场景
命令场景的核心的逻辑是调用方与不需要去关心具体的逻辑实现在这个场景中也就是点餐人员只需要把需要点的各种菜系交个小二就可以小二再把各项菜品交给各个厨师进行烹饪。也就是点餐人员不需要跟各个厨师交流只需要在统一的环境里下达命令就可以。
在这个场景中可以看到有不同的菜品山东鲁菜、四川川菜、江苏苏菜、广东粤菜、福建闽菜、浙江浙菜、湖南湘菜每种菜品都会有不同的厨师进行烹饪。而客户并不会去关心具体是谁烹饪厨师也不会去关心谁点的餐。客户只关心早点上菜厨师只关心还有多少个菜要做。而这中间的衔接的过程由小二完成。
那么在这样的一个模拟场景下可以先思考哪部分是命令模式的拆解哪部分是命令的调用者以及命令的实现逻辑。
五、用一坨坨代码实现
不考虑设计模式的情况下在做这样一个点单系统有一个类就够了
像是这样一个复杂的场景如果不知道设计模式直接开发也是可以达到目的的。但对于后续的各项的菜品扩展、厨师实现以及如何调用上会变得非常耦合难以扩展。
1. 工程结构
itstack-demo-design-14-01
└── src└── main└── java└── org.itstack.demo.design└── XiaoEr.java这里只有一个饭店小二的类通过这样的一个类实现整个不同菜品的点单逻辑。
2. 代码实现
public class XiaoEr {private Logger logger LoggerFactory.getLogger(XiaoEr.class);private MapInteger, String cuisineMap new ConcurrentHashMapInteger, String();public void order(int cuisine) {// 广东粤菜if (1 cuisine) {cuisineMap.put(1, 广东厨师烹饪鲁菜宫廷最大菜系以孔府风味为龙头);}// 江苏苏菜if (2 cuisine) {cuisineMap.put(2, 江苏厨师烹饪苏菜宫廷第二大菜系古今国宴上最受人欢迎的菜系。);}// 山东鲁菜if (3 cuisine) {cuisineMap.put(3, 山东厨师烹饪鲁菜宫廷最大菜系以孔府风味为龙头.);}// 四川川菜if (4 cuisine) {cuisineMap.put(4, 四川厨师烹饪川菜中国最有特色的菜系也是民间最大菜系。);}}public void placeOrder() {logger.info(菜单{}, JSON.toJSONString(cuisineMap));}}在这个类的实现中提供了两个方法一个方法用于点单添加菜品order()另外一个方法展示菜品的信息placeOrder()。从上面可以看到有比较多的if语句判断类型进行添加菜品那么对于这样的代码后续就需要大量的经历进行维护同时可能实际的逻辑要比这复杂的多。都写在这样一个类里会变得耦合的非常严重。
六、命令模式重构代码
接下来使用命令模式来进行代码优化也算是一次很小的重构。
命令模式可以将上述的模式拆解三层大块命令、命令实现者、命令的调用者当有新的菜品或者厨师扩充时候就可以在指定的类结构下进行实现添加即可外部的调用也会非常的容易扩展。
1. 工程结构
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命令模式模型结构 从上图可以看到整体分为三大块命令实现(菜品)、逻辑实现(厨师)、调用者(小二)以上这三面的实现就是命令模式的核心内容。经过这样的拆解就可以非常方面的扩展菜品、厨师对于调用者来说这部分都是松耦合的在整体的框架下可以非常容易加入实现逻辑。
2. 代码实现
2.1 抽象命令定义(菜品接口)
/*** 博客https://bugstack.cn - 沉淀、分享、成长让自己和他人都能有所收获* 公众号bugstack虫洞栈* Create by 小傅哥(fustack) 2020** 菜系* 01、山东鲁菜——宫廷最大菜系以孔府风味为龙头。* 02、四川川菜——中国最有特色的菜系也是民间最大菜系。* 03、江苏苏菜——宫廷第二大菜系古今国宴上最受人欢迎的菜系。* 04、广东粤菜——国内民间第二大菜系国外最有影响力的中国菜系可以代表中国。* 05、福建闽菜——客家菜的代表菜系。* 06、浙江浙菜——中国最古老的菜系之一宫廷第三大菜系。* 07、湖南湘菜——民间第三大菜系。* 08、安徽徽菜——徽州文化的典型代表。*/
public interface ICuisine {void cook(); // 烹调、制作}这是命令接口类的定义并提供了一个烹饪方法。后面会选四种菜品进行实现。
2.2 具体命令实现(四种菜品)
广东粤菜
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()。命令的实现过程可以是按照逻辑进行添加补充目前这里抽象的比较简单只是模拟一个烹饪的过程相当于同时厨师进行菜品烹饪。
2.3 抽象实现者定义(厨师接口)
public interface ICook {void doCooking();}这里定义的是具体的为命令的实现者这里也就是菜品对应的厨师烹饪的指令实现。
2.4 实现者具体实现(四类厨师)
粤菜厨师
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(四川厨师烹饪川菜中国最有特色的菜系也是民间最大菜系。);}}这里是四类不同菜品的厨师在这个实现的过程是模拟打了日志相当于通知了厨房里具体的厨师进行菜品烹饪。从以上可以看到当我们需要进行扩从的时候是可以非常方便的进行添加的每一个类都具备了单一职责原则。
2.5 调用者(小二)
public class XiaoEr {private Logger logger LoggerFactory.getLogger(XiaoEr.class);private ListICuisine cuisineList new ArrayListICuisine();public void order(ICuisine cuisine) {cuisineList.add(cuisine);}public synchronized void placeOrder() {for (ICuisine cuisine : cuisineList) {cuisine.cook();}cuisineList.clear();}}在调用者的具体实现中提供了菜品的添加和菜单执行烹饪。这个过程是命令模式的具体调用通过外部将菜品和厨师传递进来而进行具体的调用。
3. 测试验证
3.1 编写测试类
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);这里分别添加了四种菜品给小二。最后是下单这个是具体命令实现的操作相当于把小二手里的菜单传递给厨师。当然这里也可以提供删除和撤销也就是客户取消了自己的某个菜品。
3.2 测试结果
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从上面的测试结果可以看到我们已经交给调用者(小二)的点单由不同的厨师具体实现(烹饪)。此外当我们需要不同的菜品时候或者修改时候都可以非常方便的添加和修改在具备单一职责的类下都可以非常方便的扩展。
七、总结
从以上的内容和例子可以感受到命令模式的使用场景需要分为三个比较大的块命令、实现、调用者而这三块内容的拆分也是选择适合场景的关键因素经过这样的拆分可以让逻辑具备单一职责的性质便于扩展。通过这样的实现方式与if语句相比降低了耦合性也方便其他的命令和实现的扩展。但同时这样的设计模式也带来了一点问题就是在各种命令与实现的组合下会扩展出很多的实现类需要进行管理。设计模式的学习一定要勤加练习哪怕最开始是模仿实现也是可以的多次的练习后再去找到一些可以优化的场景并逐步运用到自己的开发中。提升自己对代码的设计感觉让代码结构更加清晰易扩展。