共计 4177 个字符,预计需要花费 11 分钟才能阅读完成。
一、命令模式介绍
1. 解决的问题
次要解决在零碎中,行为请求者和行为实现者紧耦合的问题。
2. 定义
命令模式 是一种行为设计模式,它可将申请转换为一个蕴含与申请相干的所有信息的独立对象。这个转换会依据不同的申请将办法参数化、提早申请执行或将其放入队列中,且能实现可撤销操作。
3. 利用场景
- 须要通过操作来参数化对象,可应用命令模式。
- 将操作放入队列中、提早操作的执行或者近程执行操作,可应用命令模式。
- 实现操作回滚性能,可应用命令模式。
二、命令模式优缺点
1. 长处
- 繁多职责准则:能够解耦触发和执行操作的类。
- 开闭准则:能够在不批改已有客户端代码的状况下,在程序中创立新的命令
- 能够履行撤销和复原性能。
- 能够实现操作的提早执行。
- 能够将一组简略命令组合成一个简单命令。
2. 毛病
- 代码可能会变得更加简单,因为在发送者和接收者之间减少了一个全新的档次。
三、命令模式利用实例:扫码点餐
1. 实例场景
往年五一五天假,很多小伙伴可能以及急不可待地要出去玩了。进来除了看风光以外,最重要的就是体验一下当地的美食。找到心仪的店,当然少不了排队,排队的同时服务员会给一个二维码提前点餐了,当咱们选好了想要吃的美食,确定下单,后盾零碎主动将订单打印给不同的厨师。
这时,咱们的订单就是一个命令,它在厨师制作之前始终在队列中期待。命令蕴含制作这些美食的所有信息。厨师能够依据这个订单间接制作,不须要和咱们确认订单信息。
明天,咱们就以扫码点餐为例,介绍一下命令模式。
2. 命令模式实现
2.1 工程构造
command-pattern
└─ src
├─ main
│ └─ java
│ └─ org.design.pattern.command
│ ├─ model
│ │ ├─ cook
│ │ │ ├─ Cook.java
│ │ │ └─ impl
│ │ │ ├─ ChiefCook.java
│ │ │ └─ CustomCook.java
│ │ └─ dish
│ │ ├─ Dish.java
│ │ └─ impl
│ │ ├─ BraisedIntestines.java
│ │ ├─ FriedPeanuts.java
│ │ ├─ LocalPotChicken.java
│ │ └─ ShreddedCabbage.java
│ └─ service
│ └─ OrderService.java
│ └─ impl
│ └─ OrderServiceImpl.java
└─ test
└─ java
└─ org.design.pattern.command
└─ OrderServiceTest.java
2.2 代码实现
2.2.1 实体类
厨师接口
/**
* 厨师接口
*/
public interface Cook {
/**
* 做饭
* @param dishName 菜名
*/
void cooking(String dishName);
}
主厨实体类
/**
* 主厨
*/
@Slf4j
public class ChiefCook implements Cook {
/**
* 做饭
*
* @param dishName 菜名
*/
@Override
public void cooking(String dishName) {log.info("主厨制作{}", dishName);
}
}
一般厨师实体类
/**
* 一般厨师
*/
@Slf4j
public class CustomCook implements Cook {
/**
* 做饭
*
* @param dishName 菜名
*/
@Override
public void cooking(String dishName) {log.info("一般厨师制作{}", dishName);
}
}
美食接口
/**
* 美食接口
*/
public abstract class Dish {
/**
* 厨师
*/
protected Cook cook;
public Dish(Cook cook) {this.cook = cook;}
/**
* 制作
*/
abstract public void cook();}
九转大肠实体类
/**
* 九转大肠
*/
public class BraisedIntestines extends Dish {public BraisedIntestines(Cook cook) {super(cook);
}
/**
* 制作
*/
@Override
public void cook() {this.cook.cooking("九转大肠");
}
}
油炸花生米实体类
/**
* 油炸花生米
*/
public class FriedPeanuts extends Dish {public FriedPeanuts(Cook cook) {super(cook);
}
/**
* 制作
*/
@Override
public void cook() {this.cook.cooking("油炸花生米");
}
}
地锅鸡实体类
/**
* 地锅鸡
*/
public class LocalPotChicken extends Dish {public LocalPotChicken(Cook cook) {super(cook);
}
/**
* 制作
*/
@Override
public void cook() {this.cook.cooking("地锅鸡");
}
}
手撕包菜实体类
/**
* 手撕包菜
*/
public class ShreddedCabbage extends Dish {public ShreddedCabbage(Cook cook) {super(cook);
}
/**
* 制作
*/
@Override
public void cook() {this.cook.cooking("手撕包菜");
}
}
2.2.2 服务类
点餐服务接口
/**
* 点餐服务接口
*/
public interface OrderService {
/**
* 点菜
* @param dish 菜
*/
void order(Dish dish);
/**
* 下单
*/
void placeOrder();}
点餐服务实现类
/**
* 点餐服务实现类
*/
public class OrderServiceImpl implements OrderService {private List<Dish> dishList = new ArrayList<>();
/**
* 点菜
*
* @param dish 菜
*/
@Override
public void order(Dish dish) {dishList.add(dish);
}
/**
* 下单
*/
@Override
public synchronized void placeOrder() {for (Dish dish : dishList) {dish.cook();
}
dishList.clear();}
}
2.3 测试验证
2.3.1 测试验证类
public class OrderServiceTest {
@Test
public void testPlaceOrder() {Cook chiefCook = new ChiefCook();
Cook customCook = new CustomCook();
Dish braisedIntestines = new BraisedIntestines(chiefCook);
Dish localPotChicken = new LocalPotChicken(chiefCook);
Dish friedPeanuts = new FriedPeanuts(customCook);
Dish shreddedCabbage = new ShreddedCabbage(customCook);
OrderService orderService = new OrderServiceImpl();
orderService.order(braisedIntestines);
orderService.order(localPotChicken);
orderService.order(friedPeanuts);
orderService.order(shreddedCabbage);
orderService.placeOrder();}
}
2.3.2 测试后果
21:08:41.617 [main] INFO o.d.p.c.model.cook.impl.ChiefCook - 主厨制作九转大肠
21:08:41.620 [main] INFO o.d.p.c.model.cook.impl.ChiefCook - 主厨制作地锅鸡
21:08:41.620 [main] INFO o.d.p.c.model.cook.impl.CustomCook - 一般厨师制作油炸花生米
21:08:41.620 [main] INFO o.d.p.c.model.cook.impl.CustomCook - 一般厨师制作手撕包菜
Process finished with exit code 0
四、命令模式构造
-
触发者(Invoker)—— 亦称“发送者(Sender)”类负责对申请进行初始化,其中必须蕴含一个成员变量来存储对命令对象的援用。
发送者触发命令,而不向接收者这集发送申请,且发送者并不负责创立命令对象:通常会通过构造函数从客户端处获取事后生成的命令。
- 命令(Command)接口通常仅申明一个执行命令的办法。
-
具体命令(Concrete Commands)会实现各种类型的申请。
具体命令本身并不实现工作,而是会将调用委派给一个业务逻辑对象,当然为了简化代码,也合并该对象。
接管对象执行办法所需的参数可申明为具体命令的成员对象,同时能够将命令对象设为不可变,仅容许通过结构早函数来对这些成员变量进行初始化。
-
接收者(Receiver)类蕴含局部业务逻辑。
基本上,任何对象都能够作为接收者。绝大部分命令只解决如何将申请传递给接收者的细节,接收者自行实现理论的工作。
-
客户端(Client)会创立并配置具体命令对象。
客户端必须将接收者实体在内的所有申请参数传递给命令的构造函数,之后,生成的命令就能够与一个或多个发送者相关联。
设计模式并不难学,其自身就是多年教训提炼出的开发指导思想,关键在于多加练习,带着应用设计模式的思维去优化代码,就能构建出更正当的代码。
源码地址:https://github.com/yiyufxst/design-pattern-java
参考资料:
小博哥重学设计模式:https://github.com/fuzhengwei/itstack-demo-design
深刻设计模式:https://refactoringguru.cn/design-patterns/catalog