JAVA【设计模式】命令模式
一、定义
命令模式:将一个请求封装为一个对象,使发出请求的责任和执行请求过程分隔开。这样两者之间通过命令对象进行沟通,便于将命令对象进行储存、传递,增强。
二、示例:
模拟场景:
1、餐厅点菜,菜品分类为:⼭东(鲁菜)、四川(川菜)、江苏(苏菜)、⼴东(粤菜)、福建(闽菜)、浙江(浙菜)、湖南(湘菜)等,每个菜肴都有对应的厨师炒出来,例如湖南厨师炒湘菜,广东厨师炒粤菜。客户向店小二提出炒什么菜肴的请求,就会有对应的厨师去处理。
传统编码
通过if实现,客气请求不同的类型,炒出什么样的菜。例如类型增多,代码会变的很臃肿
package com.qf.design.behavior.command.tradition;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
public class XiaoER {
private Logger logger= LoggerFactory.getLogger(XiaoER.class);
private Map<Integer,String> map=new HashMap<>();
public void order(int cusine){
//传统的编码方式所有的情况都在一个方法下面
if (cusine==1){
map.put(1, "⼴东厨师,烹饪鲁菜,宫廷最⼤菜系,以孔府⻛味为⻰头");
}
if (cusine==2){
map.put(2, "江苏厨师,烹饪苏菜,宫廷第⼆⼤菜系,古今国宴上最受⼈欢迎的菜系");
}
if (cusine==3){
map.put(3, "⼭东厨师,烹饪鲁菜,宫廷最⼤菜系,以孔府⻛味为⻰头");
}
if (cusine==4){
map.put(4, "四川厨师,烹饪川菜,中国最有特⾊的菜系,也是⺠间最⼤菜系。");
}
}
public void placeOrder(){
logger.info("菜单{}", JSON.toJSONString(map));
}
}
测试:ApiTest
package com.qf.design.behavior.command.tradition;
public class ApiTest {
public static void main(String[] args) {
XiaoER xiaoER=new XiaoER();
xiaoER.order(1);
xiaoER.order(2);
xiaoER.order(3);
xiaoER.order(4);
xiaoER.placeOrder();
}
}
命令模式设计
定义做菜的接口,由各个厨师具体实现
package com.qf.design.behavior.command.design.cook;
public interface ICook {
/**
* 做菜
*/
void cook();
}
四川厨师
package com.qf.design.behavior.command.design.cook.impl;
import com.qf.design.behavior.command.design.cook.ICook;
import com.qf.design.behavior.command.tradition.XiaoER;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SiChuangCookImpl implements ICook {
private Logger logger= LoggerFactory.getLogger(XiaoER.class);
@Override
public void cook() {
logger.info("四川厨师,烹饪川菜,中国最有特⾊的菜系,也是⺠间最⼤菜系。");
}
}
⼭东厨师
package com.qf.design.behavior.command.design.cook.impl;
import com.qf.design.behavior.command.design.cook.ICook;
import com.qf.design.behavior.command.tradition.XiaoER;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ShangDongCookImpl implements ICook {
private Logger logger= LoggerFactory.getLogger(XiaoER.class);
@Override
public void cook() {
logger.info("⼭东厨师,烹饪鲁菜,宫廷最⼤菜系,以孔府⻛味为⻰头");
}
}
江苏厨师
package com.qf.design.behavior.command.design.cook.impl;
import com.qf.design.behavior.command.design.cook.ICook;
import com.qf.design.behavior.command.tradition.XiaoER;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JiangSuCookImpl implements ICook {
private Logger logger= LoggerFactory.getLogger(XiaoER.class);
@Override
public void cook() {
logger.info("江苏厨师,烹饪苏菜,宫廷第⼆⼤菜系,古今国宴上最受⼈欢迎的菜系");
}
}
⼴东厨师
package com.qf.design.behavior.command.design.cook.impl;
import com.qf.design.behavior.command.design.cook.ICook;
import com.qf.design.behavior.command.tradition.XiaoER;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class GuangDongCookImpl implements ICook {
private Logger logger= LoggerFactory.getLogger(XiaoER.class);
@Override
public void cook() {
logger.info("⼴东厨师,烹饪鲁菜,宫廷最⼤菜系,以孔府⻛味为⻰头");
}
}
定义每个菜肴的接口,由各个菜肴具体实现
package com.qf.design.behavior.command.design.cusine;
public interface ICusine {
void cook();
}
四川菜
package com.qf.design.behavior.command.design.cusine.impl;
import com.qf.design.behavior.command.design.cook.ICook;
import com.qf.design.behavior.command.design.cusine.ICusine;
public class SiChuangCusineImpl implements ICusine {
private ICook cook;
public SiChuangCusineImpl(ICook cook){
this.cook=cook;
}
@Override
public void cook() {
cook.cook();
}
}
山东菜
package com.qf.design.behavior.command.design.cusine.impl;
import com.qf.design.behavior.command.design.cook.ICook;
import com.qf.design.behavior.command.design.cusine.ICusine;
public class ShangDongCusineImpl implements ICusine {
private ICook cook;
public ShangDongCusineImpl(ICook cook){
this.cook=cook;
}
@Override
public void cook() {
cook.cook();
}
}
江苏菜
package com.qf.design.behavior.command.design.cusine.impl;
import com.qf.design.behavior.command.design.cook.ICook;
import com.qf.design.behavior.command.design.cusine.ICusine;
public class JiangSuCusineImpl implements ICusine {
private ICook cook;
public JiangSuCusineImpl(ICook cook){
this.cook=cook;
}
@Override
public void cook() {
cook.cook();
}
}
粤菜
package com.qf.design.behavior.command.design.cusine.impl;
import com.qf.design.behavior.command.design.cook.ICook;
import com.qf.design.behavior.command.design.cusine.ICusine;
public class GuangdongCusineImpl implements ICusine {
private ICook cook;
public GuangdongCusineImpl(ICook cook){
this.cook=cook;
}
@Override
public void cook() {
cook.cook();
}
}
店小二负责接受客人的点单信息,转发至厨师们去实现
package com.qf.design.behavior.command.design;
import com.qf.design.behavior.command.design.cusine.ICusine;
import java.util.ArrayList;
import java.util.List;
public class Xiaoer {
private List<ICusine> cusineList=new ArrayList<>();
public void order(ICusine cusine){
cusineList.add(cusine);
}
public synchronized void placeOrder(){
for (ICusine iCusine : cusineList) {
iCusine.cook();
}
cusineList.clear();
}
}
测试:ApiTest
package com.qf.design.behavior.command.design;
import com.qf.design.behavior.command.design.cook.ICook;
import com.qf.design.behavior.command.design.cook.impl.GuangDongCookImpl;
import com.qf.design.behavior.command.design.cook.impl.JiangSuCookImpl;
import com.qf.design.behavior.command.design.cook.impl.ShangDongCookImpl;
import com.qf.design.behavior.command.design.cook.impl.SiChuangCookImpl;
import com.qf.design.behavior.command.design.cusine.ICusine;
import com.qf.design.behavior.command.design.cusine.impl.GuangdongCusineImpl;
import com.qf.design.behavior.command.design.cusine.impl.JiangSuCusineImpl;
import com.qf.design.behavior.command.design.cusine.impl.ShangDongCusineImpl;
import com.qf.design.behavior.command.design.cusine.impl.SiChuangCusineImpl;
public class ApiTest {
public static void main(String[] args) {
ICook siChuangCook = new SiChuangCookImpl();
ICook JiangSuCookCook = new JiangSuCookImpl();
ICook ShangDongCookCook = new ShangDongCookImpl();
ICook GuangDongCook = new GuangDongCookImpl();
ICusine siChuangCusine = new SiChuangCusineImpl(siChuangCook);
ICusine jiangSuCusine = new JiangSuCusineImpl(JiangSuCookCook);
ICusine guangdongCusine = new GuangdongCusineImpl(GuangDongCook);
ICusine shangDongCusine = new ShangDongCusineImpl(ShangDongCookCook);
Xiaoer xiaoer = new Xiaoer();
xiaoer.order(siChuangCusine);
xiaoer.order(jiangSuCusine);
xiaoer.order(guangdongCusine);
xiaoer.order(shangDongCusine);
xiaoer.placeOrder();
}
}
UML关系图
总结:
从以上的内容和例⼦可以感受到,命令模式的使⽤场景需要分为三个⽐较⼤的块; 命令 、 实现 、调⽤者 ,⽽这三块内容的拆分也是选择适合场景的关键因素,经过这样的拆分可以让逻辑具备单⼀职责的性质,便于扩展。
通过这样的实现⽅式与if语句相⽐,降低了耦合性也⽅便其他的命令和实现的扩展。但同时这样的设计模式也带来了⼀点问题,就是在各种命令与实现的组合下,会扩展出很多的实现类,需要进⾏管理。