行为型模式——命令模式

例子

假设有一个快餐店,而我是该餐厅的点餐服务员,那么我一天的工作应该是这样的:当某位客人点餐或者打开订餐电话后,我会把他的需求写在清单上,然后交给厨房,客人不用关心是哪些厨师帮他炒菜。我们餐厅还可以满足客人需要的定时服务,比如客人可能当前正在回家的路上,要求1小时后才开始炒他的才,只要订单还在,厨师就不会忘记,客人也可以很方便地撤销订单,另外如果有太多的客人点餐,厨房就可以按照订单的顺序排队炒菜。

这些记录着订餐信息的清单,便是命令模式中的命令对象。

模式动机

1.将请求发送者和接收者完全解耦

2.发送者与接收者之间没有直接引用关系

3.发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求

模式结构

Command(抽象命令类):抽象命令类一般是一个抽象类接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。

ConcreteCommand(具体命令类):具体命令类是抽象命令类的子类,实现了在抽象命令类中的方法,它对应具体的接收者对象,将接收者对象的动作绑定其中,具体命令类在实现execute()方法时将调用接收者对象的相关操作(Action

Invoker(调用者):调用者即请求发送者,它通过命令对象来执行请求,一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系,在程序运行时可以将一个具体命令对象注入其中,再调用具体命令对象的excute()方法,从而实现简介调用请求接收者的相关操作

Receiver(接收者):接收者执行与请求相关的操作,具体实现对请求的业务处理

如何实现

命令模式的本质是对请求进行封装

一个请求对应于一个命令,将发出命令的责任和执行命令的责任分开

命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求如何被接收操作是否被执行何时被执行以及怎么被实现

分析问题

客人即调用者,厨房即接收者。我们需要将二者解耦即在加入服务员一角色,当客人点餐时将客人发出的点餐命令交给厨房即可。同时服务员可以负责订单的日志记录、撤回等功能。

代码

饭店后厨类

public class Cook {
    //厨师自身的方法
    public void makefanqie(String table,String num){
        System.out.println("张师傅为"+table+"号桌做"+num+"份番茄炒蛋");
    }
    public void makechaofan(String table,String num){
        System.out.println("王师傅为"+table+"号桌做"+num+"份扬州炒饭");
    }
}

抽象命令类

//抽象命令类
public interface Command {

    public String getTable();

    public String getNum();
    public String getName();
    void execute();
}

具体命令类

//制作扬州炒饭的命令
public class ChaofanCommand implements Command{
    private Cook cook;
    String num,table;
    public ChaofanCommand(Cook cook, String num, String table){
        this.cook=cook;
        this.table=table;
        this.num=num;
    }
    @Override
    public void execute() {
        cook.makechaofan(table,num);
    }
    public String getName(){
        return "扬州炒饭";
    }
    public String getTable() {
        return table;
    }

    public String getNum() {
        return num;
    }
}
//制作番茄炒蛋的命令
public class FanqieCommand implements Command{
    private Cook cook;
    String num,table;
    //下单
    public FanqieCommand(Cook cook,String num,String table){
        this.cook=cook;
        this.table=table;
        this.num=num;
    }
    //执行命令
    @Override
    public void execute() {
        cook.makefanqie(table,num);
    }

    public String getName(){
        return "番茄炒蛋";
    }

    public String getTable() {
        return table;
    }

    public String getNum() {
        return num;
    }
}

服务员类

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

public class Waiter {
    //持有命令对象
    private List<Command> commandList=new ArrayList<Command>();

    //设置订单
    public void SetCommand(Command command){
        commandList.add(command);
        Logger logger=Logger.getLogger(this.getClass().getName());
        logger.info(command.getTable()+ "号桌增加订单:"+command.getNum()+"份"+command.getName());
    }

    //取消订单
    public  void CancelOrder(Command command){
        commandList.remove(command);
        Logger logger=Logger.getLogger(this.getClass().getName());
        logger.info(command.getTable()+ "号桌取消订单:"+command.getNum()+"份"+command.getName());
    }

    //通知后厨
    public void Notify(){
        for (Command cmd:commandList) {
            cmd.execute();
        }
    }
}

客户端类

//命令模式
public class Main {
    public static void main(String[] args) {
        //店家开业准备
        Cook cook=new Cook();
        Waiter waiter=new Waiter();

        //顾客点餐
        FanqieCommand cmd1=new FanqieCommand(cook,"1","1");
        ChaofanCommand cmd2=new ChaofanCommand(cook,"2","1");
        waiter.SetCommand(cmd1);
        waiter.SetCommand(cmd2);

        //点菜完毕
        waiter.Notify();
    }
}

拓展——宏命令

宏命令(Macro Command)又称为组合命令(Composite Command),它是组合模式和命令模式联用的产物

宏命令是一个具体命令类,它拥有一个集合,在该集合中包含了对其他命令对象的引用

当调用宏命令的execute()方法时,将递归调用它所包含的每个成员命令的execute()方法。一个宏命令的成员可以是简单命令,还可以继续是宏命令

执行一个宏命令将触发多个具体命令的执行,从而实现对命令的批处理

例子及代码

当顾客购买套餐时,我们可以使用宏命令进行批量处理

我们需要更改的类只有四部分

抽象宏命令类

//抽象宏命令类
public interface MacroCommand extends Command{
    void addCommand(Command command);
    void removeCommand(Command command);
}

具体宏命令类

import java.util.ArrayList;
import java.util.List;

//具体宏命令类
public class TaocanMacroCommand implements MacroCommand{
    private Cook cook;
    String table;
    //将需要批量处理的命令寄存
    private List<Command> commandList=new ArrayList<Command>();

    public TaocanMacroCommand(Cook cook, String table) {
        this.cook = cook;
        this.table = table;
    }

    @Override
    public String getTable() {
        return table;
    }

    @Override
    public String getNum() {
        return null;
    }

    @Override
    public String getName() {
        return "套餐1";
    }

    @Override
    public void execute() {
        for (Command cmd:commandList) {
            cmd.execute();
        }
    }

    @Override
    public void addCommand(Command command) {
        commandList.add(command);
    }

    @Override
    public void removeCommand(Command command) {
        commandList.remove(command);
    }
}

服务员类

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

public class Waiter {
    //持有命令对象
    private List<Command> commandList=new ArrayList<Command>();

    //设置订单
    public void SetCommand(Command command){
        commandList.add(command);
        Logger logger=Logger.getLogger(this.getClass().getName());
        logger.info(command.getTable()+ "号桌增加订单:"+command.getNum()+"份"+command.getName());
    }
    //设置套餐
    public void SetCTaocan(MacroCommand taocan){
        commandList.add(taocan);
        Logger logger=Logger.getLogger(this.getClass().getName());
        logger.info(taocan.getTable()+ "号桌增加套餐:"+taocan.getName());
    }
    //取消订单
    public  void CancelOrder(Command command){
        commandList.remove(command);
        Logger logger=Logger.getLogger(this.getClass().getName());
        logger.info(command.getTable()+ "号桌取消订单:"+command.getNum()+"份"+command.getName());
    }
    //取消套餐
    public  void CancelTaocan(MacroCommand taocan){
        commandList.remove(taocan);
        Logger logger=Logger.getLogger(this.getClass().getName());
        logger.info(taocan.getTable()+ "号桌取消套餐:"+taocan.getName());
    }
    //通知后厨
    public void Notify(){
        for (Command cmd:commandList) {
            cmd.execute();
        }
    }

    //处理完一个人的订单后清除笔记本
    public List<Command> getCommandList() {
        return commandList;
    }
}

客户端类

//命令模式
public class Main {
    public static void main(String[] args) {
        //店家开业准备
        Cook cook=new Cook();
        Waiter waiter=new Waiter();

        //顾客1单点
        FanqieCommand cmd1=new FanqieCommand(cook,"1","1");
        ChaofanCommand cmd2=new ChaofanCommand(cook,"2","1");
        waiter.SetCommand(cmd1);
        waiter.SetCommand(cmd2);

        //顾客1点菜完毕
        waiter.Notify();
        waiter.getCommandList().clear();

        //顾客2点套餐
        FanqieCommand cmd3=new FanqieCommand(cook,"1","2");
        ChaofanCommand cmd4=new ChaofanCommand(cook,"1","2");
        TaocanMacroCommand tc=new TaocanMacroCommand(cook,"2");
        tc.addCommand(cmd3);
        tc.addCommand(cmd4);
        waiter.SetCTaocan(tc);

        //顾客2点菜完毕
        waiter.Notify();
        waiter.getCommandList().clear();
    }
}

模式优点

1.降低系统耦合度

2.新的命令可以很容易的加入到系统中,符合开闭原则

3.可以比较容易的设计一个命令队列或宏命令(组合命令)

4.为请求的撤销和恢复操作提供了一种实现方案

模式缺点

使用命令模式可能会导致某些系统过多的具体命令类(针对每一个对请求接收者的调用操作都需要设计一个具体以命令类,所以在某些系统中可能需要提供大量的命令类,这将影响命令模式的使用)

适用环境

1.系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互

2.系统需要在不同的事件指定请求,将请求排队和执行请求

3.系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作

4.系统需要将一组操作组合在一起形成宏命令

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值