当前位置: 首页 > article >正文

Java设计模式 —— 【行为型模式】命令模式(Command Pattern) 详解

文章目录

  • 模式介绍
  • 优缺点
  • 适用场景
  • 结构
  • 案例实现
      • 注意事项


模式介绍

有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么。此时希望用一种松耦合的方式来设计程序,使得请求发送者和请求接收者能够消除彼此之间的耦合关系

拿订餐来说,客人需要向厨师发送请求,但是完全不知道这些厨师的名字和联系方式,也不知道厨师炒菜的方式和步骤。 命令模式把客人订餐的请求封装成 command 对象,也就是订餐中的订单对象。这个对象可以在程序中被四处传递,就像订单可以从服务员手中传到厨师的手中。这样一来,客人不需要知道厨师的名字,从而解开了请求调用者和请求接收者之间的耦合关系。

模式定义:

命令模式是一个行为模式,它是将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行存储、传递、调用、增加与管理。


优缺点

优点:

  • 类间解耦: 调用者角色与接收者角色之间没有任何依赖关系,调用者实现功能时只需调用Command 抽象类的execute方法就可以,不需要了解到底是哪个接收者执行。
  • 可扩展性: Command的子类可以非常容易地扩展,而调用者Invoker和高层次的模块Client不产生严 重的代码耦合。
  • 命令模式结合其他模式会更优秀: 命令模式可以结合责任链模式,实现命令族解析任务;结合模板方法模式,则可以减少 Command子类的膨胀问题。

缺点:

  • 如果有N个命令,Command的子类就可不是几个,而是N个,这个类膨胀得非常大。

适用场景

  • 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
  • 系统需要在不同的时间指定请求、将请求排队和执行请求。
  • 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。

结构

命令模式包含以下主要角色:

  • 抽象命令类(Command)角色: 定义命令的接口,声明执行的方法。
  • 具体命令(Concrete Command)角色: 具体的命令,实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
  • 实现者/接收者(Receiver)角色: 接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
  • 调用者/请求者(Invoker)角色: 要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
    在这里插入图片描述

案例实现

以生活中的开灯关灯为例: 在小丽家装了智能家居以后,老王迫不及待的体验了一下遥控关灯开灯功能,这可比手动抹黑找开关方便多了,我们先来分析命令模式的角色在该案例中由谁来充当。

遥控器: 就是调用者角色,由她来发起命令(持有命令)。
电灯: 就是接收者角色,真正命令执行的对象(被命令持有)。

UML类图如下:
在这里插入图片描述
抽象命令类:

public interface Command {
    void execute();
}

开灯,关灯命令【具体命令类】:

public class LightOffCommand implements Command{
    private LightReceiver lightReceiver;

    public LightOffCommand(LightReceiver lightReceiver) {
        this.lightReceiver = lightReceiver;
    }

    @Override
    public void execute() {
        lightReceiver.off();
    }
}
public class LightOnCommand implements Command{
    private LightReceiver lightReceiver;

    public LightOnCommand(LightReceiver lightReceiver) {
        this.lightReceiver = lightReceiver;
    }

    @Override
    public void execute() {
        lightReceiver.on();
    }
}

电灯【接收者角色】:

public class LightReceiver {
    public void on(){
        System.out.println("电灯打开了...");
    }

    public void off(){
        System.out.println("电灯关闭了...");
    }
}

遥控器【请求者角色】:

public class RemoteController {
    private Command command;

    //添加命令
    public void setCommand(Command command) {
        this.command = command;
    }

    public void executeCommand(){
        if (command != null){
            command.execute();
        }
    }
}

测试:

public class Client {
    public static void main(String[] args) {
        //遥控器(请求者)
        RemoteController robotInvoker = new RemoteController();
        //电灯(接收者)
        LightReceiver lightReceiver = new LightReceiver();
        //开灯
        LightOnCommand lightOnCommand = new LightOnCommand(lightReceiver);
        robotInvoker.setCommand(lightOnCommand);
        robotInvoker.executeCommand();
        //关灯
        LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver);
        robotInvoker.setCommand(lightOffCommand);
        robotInvoker.executeCommand();
    }
}

在这里插入图片描述

注意事项

  • Command 接口非常简单,通常只有一个execute方法,如果要支持撤销操作的话,再加一个unexecute方法;
  • 每个具体的命令类内部封装了实际执行命令的那个类(Recevier),或者那些类,以及执行需要的数据;
  • 每个具体命令类只完成一个请求,有多少个请求就有多少个命令;
  • Invoker类只认识接口Command,其他的都不认识;
  • 客户端类负责生成命令,并通过Invoker组装执行。

http://www.kler.cn/a/471643.html

相关文章:

  • Linux的proc目录与什么有关?【以及它里面的文件各自记录着什么信息】
  • QT 端口扫描附加功能实现 端口扫描5
  • 前端基础--网络
  • excel如何将小数转换为百分比
  • LabVIEW计算机软件著作权
  • 形态学:图像处理中的强大工具
  • doris 2.1 Data Queries Common Table Expression UDF 学习笔记
  • 【LeetCode】4. 去重的效率提升
  • 基于CentOS的Docker + Nginx + Gitee + Jenkins部署总结(进阶)-- 接入钉钉通知功能
  • C# 对象和类型(结构)
  • GOAT‘S AI早鸟报Part9
  • 2019年IMO第2题
  • 深入解析Java 8中的Lambda表达式与函数式接口
  • MATLAB语言的数据结构
  • 【Javascript Day2】
  • 32单片机从入门到精通之数据处理——传感器接口(十二)
  • kafka搭建
  • 代码随想录day38 动态规划6
  • 06-RabbitMQ基础
  • 【源码+文档+调试讲解】项目申报小程序
  • 一次压测的记录笔记
  • 基于 GEE 的 MODIS 数据集 NDVI 时间序列动画
  • FPGA与IC:选哪个更好?
  • 基于微信小程序疫苗预约系统ssm+论文源码调试讲解
  • 计算机网络之---网络拓扑
  • 教育咨询系统架构与功能分析