提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
1. 需求
用代码实现在路边买羊肉串,老板烤羊肉串的过程
2. 代码版本1.0
2.1 UML类图
2.2 烤肉串者类
//烤肉串者
public class Barbecuer {
//烤羊肉
public void bakeMutton(){
System.out.println("烤羊肉串");
}
//烤鸡翅
public void bakeChickenWing(){
System.out.println("烤鸡翅");
}
}
2.3 客户端代码
Barbecuer boy = new Barbecuer();
boy.bakeMutton();
boy.bakeMutton();
boy.bakeMutton();
boy.bakeChickenWing();
2.4 弊端
如果用户多了,请求多了,老板就容易乱了。因此需要命令模式
3. 命令模式
3.1 概念
命令模式(Command),将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
3.2 优点
- 较容易地设计一个命令队列。
- 在需要的情况下,可以较容易地将命令记入日志。
- 允许接收请求的一方决定是否要否决请求。
- 可以容易地实现对请求的撤销和重做。
- 由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易。
- 把请求一个操作的对象与知道怎么执行一个操作的对象分割开。
3.3 UML类图
3.4 案例代码
3.4.1 Command类
Command类,用来声明执行操作的接口。
//抽象命令类
public abstract class Command {
protected Receiver receiver;
public Command(Receiver receiver) {
this.receiver = receiver;
}
//执行命令
public abstract void excuteCommand();
}
3.4.2 ConcreteCommand类
ConcreteCommand类,将一个接收者对象绑定于一个动作,调用接收者相应的操作,以实现executeCommand。
//具体命令类
public class ConcreteCommand extends Command {
public ConcreteCommand(Receiver receiver){
super(receiver);
}
public void excuteCommand(){
receiver.action();
}
}
3.4.3 Invoker类
Invoker类,要求该命令执行这个请求。
public class Invoker {
private Command command;
public void setCommand(Command command){
this.command = command;
}
public void excuteCommand(){
command.excuteCommand();
}
}
3.4.4 Receiver类
Receiver类,知道如何实施与执行一个与请求相关的操作,任何类都可能作为一个接收者。
public class Receiver {
public void action(){
System.out.println("执行请求");
}
}
3.4.5 客户端代码
客户端代码,创建一个具体命令对象并设定它的接收者。
public class Client {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker();
invoker.setCommand(command);
invoker.excuteCommand();
}
}
4. 需求变更
使用命令模式实现饭店点菜的代码
5. 代码版本2.0(命令模式实现)
5.1 UML类图
5.2 抽象命令类
//抽象命令类
public abstract class Command {
protected Barbecuer receiver;
public Command(Barbecuer receiver){
this.receiver = receiver;
}
//执行命令
public abstract void excuteCommand();
}
5.3 具体命令类
public class BakeMuttonCommand extends Command{
public BakeMuttonCommand(Barbecuer receiver) {
super(receiver);
}
@Override
public void excuteCommand() {
receiver.bakeMutton();
}
}
public class BakeChickenWingCommand extends Command{
public BakeChickenWingCommand(Barbecuer receiver) {
super(receiver);
}
@Override
public void excuteCommand() {
receiver.bakeChickenWing();
}
}
5.4 服务员类
//服务员类
public class Waiter {
private Command command;
//设置订单
public void setOrder(Command command){
this.command = command;
}
//通知执行
public void notifyCommand(){
command.excuteCommand();
}
}
5.5 客户端代码
Barbecuer boy = new Barbecuer();//烤肉厨师
Command bakeMuttonCommand1 = new BakeMuttonCommand(boy);
Command bakeChickenWingCommand1 = new BakeChickenWingCommand(boy);
Waiter girl = new Waiter(); //服务员
//开门营业
girl.setOrder(bakeMuttonCommand1);//下单烤羊肉串
girl.notifyCommand();//通知厨师烤肉
girl.setOrder(bakeMuttonCommand1);//下单烤羊肉串
girl.notifyCommand();//通知厨师烤肉
girl.setOrder(bakeChickenWingCommand1);//下单烤羊肉串
girl.notifyCommand();//通知厨师烤肉
5.6 不足
- 真实的情况其实并不是用户点一个菜,服务员就通知厨房去做一个,应该是点完烧烤后,服务员一次通知制作。
- 如果此时鸡翅没了,不应该是客户来判断是否还有,,应该是服务员或烤肉串者来否决这个请求。
- 客户到底点了哪些烧烤或饮料,这是需要记录日志的,以备收费,也包括后期的统计。
- 客户完全有可能因为点的肉串太多而考虑取消一些还没有制作的肉串。
6. 代码版本3.0
6.1 服务员类
public class Waiter {
private ArrayList<Command> orders = new ArrayList<>();
//设置订单
public void setOrder(Command command){
String className = command.getClass().getSimpleName();
if (className.equals("BakeChickenWingCommand")){//模拟没货的情况
System.out.println("服务员:鸡翅没有了");
}else {
this.orders.add(command);
System.out.println("增加订单:"+className+"时间:"+getNowTime());
}
}
//取消订单
public void cancelOrder(Command command){
String className = command.getClass().getSimpleName();
orders.remove(command);
System.out.println("取消订单"+className+"时间:"+getNowTime());
}
//通知执行
public void notifyCommand(){
for (Command order : orders) {
order.excuteCommand();
}
}
private String getNowTime(){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
return simpleDateFormat.format(new Date()).toString();
}
}
6.2客户端代码
Barbecuer boy = new Barbecuer();
Command bakeMuttonCommand1 = new BakeMuttonCommand(boy);
Command bakeChickenWingCommand1 = new BakeChickenWingCommand(boy);
Waiter girl = new Waiter();
System.out.println("开门营业,顾客点菜");
girl.setOrder(bakeMuttonCommand1);
girl.setOrder(bakeMuttonCommand1);
girl.setOrder(bakeMuttonCommand1);
girl.setOrder(bakeMuttonCommand1);
girl.setOrder(bakeMuttonCommand1);
girl.cancelOrder(bakeMuttonCommand1);
girl.setOrder(bakeChickenWingCommand1);
System.out.println("点菜完毕,通知厨房烧菜");
girl.notifyCommand();