您现在的位置是:首页 > 正文

设计模式(19)命令模式

2024-01-30 21:33:42阅读 0

一、介绍:

1、定义:命令模式(Command Pattern)是一种行为设计模式,它将请求封装为一个对象,从而使你可以使用不同的请求对客户端进行参数化。命令模式还支持请求的排队、记录日志、撤销操作等功能。

2、组成结构:

(1)命令接口(Command):定义执行命令的方法,可以是抽象类或接口。

public interface Command {
    void execute();
}

(2)具体命令类(Concrete Command):实现命令接口,封装了具体的请求和接收者,负责执行请求。

/**
 * 具体的命令实现
 */
public class ConcreteCommand implements Command {
 
	/**
	 * 持有相应的接收者对象
	 */
	private Receiver receiver = null;
 
	/**
	 * 构造方法,传入相应的接收者对象
	 * 
	 * @param receiver 相应的接收者对象
	 */
	public ConcreteCommand(Receiver receiver) {
		this.receiver = receiver;
	}
 
	/**
	 * 执行命令
	 */
	@Override
	public void execute() {
		// 通常会转调接收者对象的相应方法,让接收者来真正执行功能
		receiver.action();
	}
 
}

(3)接收者类(Receiver):命令接受者对象,定义了命令接受者可以做的事情。执行实际的操作,命令对象将请求委托给接收者来执行。

public class Receiver {
    public void action() {
        System.out.println("执行具体操作");
    }
}

(4)调用者类(Invoker):Invoker类是具体命令的接收者,用于接收客户的所有命令,然后将命令转达给执行者,执行这些命令。

public class Invoker {
    private Command command;
    
    public void setCommand(Command command) {
        this.command = command;
    }
    
    public void executeCommand() {
        command.execute();
    }
}

客户端(Client):创建具体的命令对象,并将其分配给调用者来执行。

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.executeCommand();
    }
}

3、优点

  • 能够比较容易的设计一个命令队列
  • 在需要的情况下,可以比较容易地将命令记入日志
  • 允许接收请求的一方决定是否要解决请求
  • 可以容易的实现对请求的撤销和重做
  • 容易扩展新的命令类
  • 能够把请求一个操作的对象,与知道怎么执行一个操作的对象分隔开

二、demo:

1、点餐:服务员充当命令委托角色,在顾客和厨师之间松耦合

(1)命令:

//顾客抽象命令
public abstract class Command {

    public Integer count;

    public Integer getCount() {
        return count;
    }

    public void setCount(Integer count) {
        this.count = count;
    }

    protected Cook receiver;

    public Command(Cook receiver,int count) {
        this.receiver = receiver;
        this.count = count;
    }

    public abstract void execute();
}




//具体命令1
public class BakeBeefCommand extends Command {
    public BakeBeefCommand(Cook receiver,int count) {
        super(receiver,count);
    }

    @Override
    public void execute() {
        receiver.bakeBeef();
    }
}


//具体命令2
public class BakeMuttonCommand extends  Command{
    public BakeMuttonCommand(Cook receiver,int count) {
        super(receiver,count);
    }

    @Override
    public void execute() {
        receiver.bakeMutton();
    }
}

(2)命令实际接收者 厨师

public class Cook {

    public void bakeMutton(){
        System.out.println("烤羊肉");
    }

    public void bakeBeef(){
        System.out.println("烤牛肉");
    }
}

(3)命令中转 服务员

public class Waiter {
    private List<Command> orders= new ArrayList<>();

    public void setOrder(Command command) {
        if(command.getCount() < 5){
            System.err.println("点餐失败,一份数量最小为5,count="+command.getCount());
        }else{
            System.out.println("点餐成功,记录日志,count="+command.getCount());
            this.orders.add(command);
        }
    }

    public void cancleOrder(Command command) {
        System.out.println("取消成功,记录日志,count="+command.getCount());
        this.orders.remove(command);
    }


    public void executeCommand(){
        System.out.println("***点餐结束***");
        for (Command comm : orders) {
            comm.execute();
        }
    }
}

客户端

public static void main(String[] args) {
        Cook receiver = new Cook();
        Waiter waiter = new Waiter();
        Command muttonCommand = new BakeMuttonCommand(receiver,1);
        waiter.setOrder(muttonCommand);
        muttonCommand = new BakeMuttonCommand(receiver,5);
        waiter.setOrder(muttonCommand);
        Command beefCommand = new BakeBeefCommand(receiver,6);
        waiter.setOrder(beefCommand);
        beefCommand = new BakeBeefCommand(receiver,7);
        waiter.setOrder(beefCommand);
        //临时取消
        waiter.cancleOrder(beefCommand);

        //全部点餐结束后执行
        waiter.executeCommand();
    }


输出:
点餐失败,一份数量最小为5,count=1
点餐成功,记录日志,count=5
点餐成功,记录日志,count=6
点餐成功,记录日志,count=7
取消成功,记录日志,count=7
***点餐结束***
烤羊肉
烤牛肉

网站文章

  • 自定义线程池

    自定义线程池

    一:参数分析 我们要想自定义线程池,必须先了解线程池的工作流程,才能自己定义线程池。下图是ThreadPoolExecutor的构造方法。 我们可以通过下面的场景理解ThreadPoolExecuto...

    2024-01-30 21:33:13
  • MobaXterm登录密码重置问题

    MobaXterm登录密码重置问题

    登录MobaXterm提示输入密码,密码输入多次后无果,密码忘记如法使用MobaXterm软件,经过查询后可采用密码重置的方式处理。使用浏览器打开如下网址:https://mobaxterm.moba...

    2024-01-30 21:33:04
  • 括号匹配数据结构

    学习分享本周学习的是数据结构的括号匹配,所谓括号匹配指的是在命令端输入一行只含有括号的代码,然后运行代码,判断每一个左括号是否有一个右括号与之对应,从而判断输入的数据是否违法代码如下:#define ...

    2024-01-30 21:32:57
  • echart图表保存为图片的两种方式

    echart图表保存为图片的两种方式

    将echarts图表和ucharts图表保存为图片

    2024-01-30 21:32:28
  • 头歌大数据——MapReduce 基础实战 答案 无解析

    头歌大数据——MapReduce 基础实战 答案 无解析

    2024-01-30 21:32:20
  • JMeter巧用计数器实现CSV数据文件设置的功能

    JMeter巧用计数器实现CSV数据文件设置的功能

    需求本次压测范围包含登录接口,但是压测环境user表用户数据量太少,和生产环境数据量不是一个量级,因此,需要先通过并发跑注册接口造用户数据需要参数化的字段是username和phone说明:本次演示的接口是示例接口,非实际生产环境接口注册接口如下:方案一:CSV 数据文件设置我们先通过代码(python或者java均可)造一定量的参数化数据写在参数化reg.txt文件中pac...

    2024-01-30 21:32:13
  • android线,android_线

    android线,android_线

    说明:android螺纹。android无非就是一个线程Main Thread和Worker Thread。(除了主线程Main Thread是Worker Thread)Main Thread 也叫...

    2024-01-30 21:31:35
  • HMM与CRF模型的使用过程存在哪些差异?

    HMM与CRF模型的使用过程存在哪些差异?

    训练后, 我们就得到了具备预测能力的新模型: lambda = CRF(w1, w2, ..., wn), 其中的模型参数已经改变.之后给定输入序列(x1, x2, ..., xn), 经过模型计算l...

    2024-01-30 21:31:28
  • Java读取文件为字符串】使用Java编程读取文件内容并将其作为字符串进行处理

    在Java中,读取文件内容需要使用文件输入流(FileInputStream)和缓冲区输入流(BufferedReader)。这是一个简单的示例,展示了如何使用Java读取文件并将其作为字符串进行处理...

    2024-01-30 21:31:21
  • flash制作车轮转动的汽车沿着路径走的动画

    flash制作车轮转动的汽车沿着路径走的动画

    二维动画制作实验报告一.实验目的1.掌握动画的概念。2.熟练Flash的界面。3.掌握Flash界面中各组成元素和功能。二.实验工具    Flash三.实验要求制作车轮转动的汽车沿着路径走。四.实验...

    2024-01-30 21:30:51