探讨命令模式及其应用

目录

  • 命令模式
    • 命令模式结构
    • 命令模式适用场景
    • 命令模式优缺点
    • 练手题目
      • 题目描述
      • 输入描述
      • 输出描述
      • 题解

命令模式

命令模式是一种行为设计模式, 它可将请求转换为一个包含与请求相关的所有信息的独立对象。 该转换让你能根据不同的请求将方法参数化、 延迟请求执行或将其放入队列中, 且能实现可撤销操作。

命令模式结构

在这里插入图片描述

  1. 发送者(Sender)——亦称 “触发者(Invoker)”——类负责对请求进行初始化,其中必须包含一个成员变量来存储对于命令对象的引用。发送者触发命令,而不向接收者直接发送请求。注意,发送者并不负责创建命令对象:它通常会通过构造函数从客户端处获得预先生成的命令。
  2. 命令(Command)接口通常仅声明一个执行命令的方法。
  3. 具体命令 (Concrete Commands)会实现各种类型的请求。具体命令自身并不完成工作,而是会将调用委派给一个业务逻辑对象。但为了简化代码,这些类可以进行合并。接收对象执行方法所需的参数可以声明为具体命令的成员变量。你可以将命令对象设为不可变,仅允许通过构造函数对这些成员变量进行初始化。
  4. 接收者(Receiver)类包含部分业务逻辑。几乎任何对象都可以作为接收者。绝大部分命令只处理如何将请求传递到接收者的细节,接收者自己会完成实际的工作。
  5. 客户端(Client)会创建并配置具体命令对象。客户端必须将包括接收者实体在内的所有请求参数传递给命令的构造函数。此后,生成的命令就可以与一个或多个发送者相关联了。

命令模式通用代码:

//抽象接收者
public abstract class Receiver{
	public abstract void operation();
}

//具体接收者
public class Recevier1 extends Recevier{
	public void operation(){
		...
	}
}

//通用命令接口
public interface Command{
	void execute();
}

//具体命令类
public class ConcreteCommand1 implements Command{
	private Receiver receiver;
	
	public ConcreteCommand1(Receiver _receiver){
		 this.receiver = _receiver;
	}
	
	public void execute(){
		this.receiver.operation();
	}
}

//调用者类
public class Invoker{
	private Command command;
	
	public void setCommand(Command _command){
		this.command = _command;
	}
	
	public void executeCommand(){
		this.command.execute();
	}
	
}

//主程序类
public class Client{
	public static void main(String[] args){
		//调用者
		Invoker invoker = new Invoker();
		//接收者
		Receiver receiver1 = new Receiver1();
		//定义一个命令
		Command command = new ConcreteCommand1(receiver1);
		
		invoker.setCommand(command);
		invoker.executeCommand();
	}
}

命令模式适用场景

  1. 如果你需要通过操作来参数化对象,可使用命令模式。

    命令模式可将特定的方法调用转化为独立对象。 这一改变也带来了许多有趣的应用: 你可以将命令作为方法的参数进行传递、 将命令保存在其他对象中, 或者在运行时切换已连接的命令等。

  2. 如果你想要将操作放入队列中、操作的执行或者远程执行操作,可使用命令模式。

    同其他对象一样,命令也可以实现序列化(序列化的意思是转化为字符串),从而能方便地写入文件或数据库中。一段时间后,该字符串可被恢复成为最初的命令对象。因此,你可以延迟或计划命令的执行。但其功能远不止如此!使用同样的方式,你还可以将命令放入队列、记录命令或者通过网络发送命令。

  3. 如果你想要实现操作回滚功能,可使用命令模式。

在这里插入图片描述

**识别方法:**命令模式可以通过抽象或接口类型(发送者)中的行为方法来识别, 该类型调用另一个不同的抽象或接口类型 (接收者)实现中的方法,该实现则是在创建时由命令模式的实现封装。命令类通常仅限于一些特殊行为。

命令模式优缺点

命令模式优点:

  • 单一职责原则。你可以解耦触发和执行操作的类。
  • 开闭原则。你可以在不修改已有客户端代码的情况下在程序中创建新的命令。
  • 你可以实现撤销和恢复功能。
  • 你可以实现操作的延迟执行。
  • 你可以将一组简单命令组合成一个复杂命令。

命令模式缺点:

  • 代码可能会变得更加复杂,因为你在发送者和接收者之间增加了一个全新的层次。

练手题目

题目描述

小明去奶茶店买奶茶,他可以通过在自助点餐机上来点不同的饮品,请你使用命令模式设计一个程序,模拟这个自助点餐系统的功能。

输入描述

第一行是一个整数 n(1 ≤ n ≤ 100),表示点单的数量。

接下来的 n 行,每行包含一个字符串,表示点餐的饮品名称。

输出描述

输出执行完所有点单后的制作情况,每行输出一种饮品的制作情况。如果制作完成,输出 “XXX is ready!”,其中 XXX 表示饮品名称。

在这里插入图片描述

题解

解法一:

import java.util.Scanner;

// 枚举类表示饮料类型
enum BeverageType {
    MILKTEA, COFFEE, COLA
}

// 抽象饮料类
abstract class Beverage {
    abstract void make();
}

// 具体饮料类
class MilkTea extends Beverage {
    @Override
    public void make() {
        System.out.println("MilkTea is ready!");
    }
}

class Coffee extends Beverage {
    @Override
    public void make() {
        System.out.println("Coffee is ready!");
    }
}

class Cola extends Beverage {
    @Override
    public void make() {
        System.out.println("Cola is ready!");
    }
}

// 抽象命令类
abstract class Command {
    protected Beverage beverage;

    public Command(Beverage _beverage) {
        this.beverage = _beverage;
    }

    abstract void execute();
}

// 具体命令类
class MilkTeaCommand extends Command {
    public MilkTeaCommand() {
        super(new MilkTea());
    }

    @Override
    public void execute() {
        beverage.make();
    }
}

class CoffeeCommand extends Command {
    public CoffeeCommand() {
        super(new Coffee());
    }

    @Override
    public void execute() {
        beverage.make();
    }
}

class ColaCommand extends Command {
    public ColaCommand() {
        super(new Cola());
    }

    @Override
    public void execute() {
        beverage.make();
    }
}

// 调用者类
class Invoker {
    private Command command;

    public void setCommand(Command _command) {
        command = _command;
    }

    public void action() {
        command.execute();
    }
}

// 主类
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        try {
            Invoker invoker = new Invoker();

            int n = scanner.nextInt();
            scanner.nextLine();

            for (int i = 0; i < n; i++) {
                String type = scanner.nextLine().trim().toUpperCase();

                try {
                    switch (BeverageType.valueOf(type)) {
                        case MILKTEA:
                            invoker.setCommand(new MilkTeaCommand());
                            break;
                        case COFFEE:
                            invoker.setCommand(new CoffeeCommand());
                            break;
                        case COLA:
                            invoker.setCommand(new ColaCommand());
                            break;
                        default:
                            System.out.println("请重新输入:");
                            continue;
                    }
                    invoker.action();
                } catch (IllegalArgumentException e) {
                    System.out.println("无效的饮料类型");
                }
            }

        } catch (Exception e) {
            System.out.println("发生错误: " + e.getMessage());
        } finally {
            scanner.close();
        }
    }
}

解法二:

import java.util.Scanner;

// 命令接口
interface Command {
    void execute();
}

// 具体命令类 - 点餐命令
class OrderCommand implements Command {
    private String drinkName;
    private DrinkMaker receiver;

    public OrderCommand(String drinkName, DrinkMaker receiver) {
        this.drinkName = drinkName;
        this.receiver = receiver;
    }

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

// 接收者类 - 制作饮品
class DrinkMaker {
    public void makeDrink(String drinkName) {
        System.out.println(drinkName + " is ready!");
    }
}

// 调用者类 - 点餐机
class OrderMachine {
    private Command command;

    public void setCommand(Command command) {
        this.command = command;
    }

    public void executeOrder() {
        command.execute();
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 创建接收者和命令对象
        DrinkMaker drinkMaker = new DrinkMaker();

        // 读取命令数量
        int n = scanner.nextInt();
        scanner.nextLine();

        while (n-- > 0) {
            // 读取命令
            String drinkName = scanner.next();

            // 创建命令对象
            Command command = new OrderCommand(drinkName, drinkMaker);

            // 执行命令
            OrderMachine orderMachine = new OrderMachine();
            orderMachine.setCommand(command);
            orderMachine.executeOrder();
        }
        scanner.close();
    }
}

解法三:命令模式+工厂模式

import java.util.Scanner;

// 命令接口
interface Command {
    void execute();
}

// 具体命令类 - 点餐命令
class OrderCommand implements Command {
    private String drinkName;
    private DrinkMaker receiver;

    public OrderCommand(String drinkName, DrinkMaker receiver) {
        this.drinkName = drinkName;
        this.receiver = receiver;
    }

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

// 接收者类 - 制作饮品
class DrinkMaker {
    public void makeDrink(String drinkName) {
        System.out.println(drinkName + " is ready!");
    }
}

// 调用者类 - 点餐机
class OrderMachine {
    private Command command;

    public void setCommand(Command command) {
        this.command = command;
    }

    public void executeOrder() {
        if (command != null) {
            command.execute();
        } else {
            System.out.println("未设置命令.");
        }
    }
}

// 命令工厂类
class CommandFactory {
    private DrinkMaker drinkMaker;

    public CommandFactory(DrinkMaker drinkMaker) {
        this.drinkMaker = drinkMaker;
    }

    public Command createCommand(String drinkName) {
        return new OrderCommand(drinkName, drinkMaker);
    }
}

// 主类
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 创建接收者和工厂对象
        DrinkMaker drinkMaker = new DrinkMaker();
        CommandFactory commandFactory = new CommandFactory(drinkMaker);
        OrderMachine orderMachine = new OrderMachine();

        // 读取命令数量
        int n = scanner.nextInt();
        scanner.nextLine();

        while (n-- > 0) {
            // 读取命令
            String drinkName = scanner.nextLine().trim();

            if (drinkName.isEmpty()) {
                System.out.println("无效输入,请输入饮品名.");
                continue;
            }

            // 使用工厂创建命令对象
            Command command = commandFactory.createCommand(drinkName);

            // 设置命令并执行
            orderMachine.setCommand(command);
            orderMachine.executeOrder();
        }
        scanner.close();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/768420.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

玩玩快速冥(LeetCode50题与70题以及联系斐波那契)

一.算法快速幂 今天刷到两个题,比较有意思,还是记录一下. 先来讲讲50题. LeetCode50(Pow(x,n)) 实现 pow(x, n) &#xff0c;即计算 x 的整数 n 次幂函数&#xff08;即&#xff0c;xn &#xff09;。 这道题一看很平常啊,不就一直乘嘛,循环走一次就够了.但是很抱歉,单纯的想…

ArcTs布局入门04——相对布局 媒体查询

如果你也对鸿蒙开发感兴趣&#xff0c;加入“Harmony自习室”吧 扫描下面的二维码关注公众号。 本文将探讨相对布局与媒体查询&#xff0c;为啥把他们放到一起呢&#xff1f;主要是因为相对布局在响应式的场景下做得不太好&#xff0c;一般情况下和媒体查询&#xff08;不同尺…

移动智能终端数据安全管理方案

随着信息技术的飞速发展&#xff0c;移动设备已成为企业日常运营不可或缺的工具。特别是随着智能手机和平板电脑等移动设备的普及&#xff0c;这些设备存储了大量的个人和敏感数据&#xff0c;如银行信息、电子邮件等。员工通过智能手机和平板电脑访问企业资源&#xff0c;提高…

zed_ros2_wapper colcon 报错

问题一&#xff1a; CMake Error at CMakeLists.txt:129 (find_package): By not providing “Findnmea_msgs.cmake” in CMAKE_MODULE_PATH this project has asked CMake to find a package configuration file provided by “nmea_msgs”, but CMake did not find one. Co…

jdk17卸载后换jdk1.8遇到的问题

过程&#xff1a; 1、找到jdk17所在文件夹&#xff0c;将文件夹进行删除。&#xff08;问题就源于此&#xff0c;因为没删干净&#xff09; 2、正常下载jdk1.8&#xff0c;按照网上步骤配置环境变量&#xff0c;这里我参考的文章是&#xff1a; http://t.csdnimg.cn/Svblk …

乘用车副水箱浮球式液位计传感器

浮球式液位计概述 浮球式液位计是一种利用浮球在液体中浮动的原理来测量液位的设备&#xff0c;广泛应用于各种工业自动化控制系统中&#xff0c;如石油化工、水处理、食品饮料等行业。它通过浮球的上下运动来测量液位的高低&#xff0c;具有结构简单、安装方便、测量范围广、…

[Leetcode 136][Easy]-只出现一次的数字

目录 题目描述 具体思路 题目描述 原题链接 具体思路 ①首先看到数组中重复的数字&#xff0c;想到快慢指针&#xff0c;但是数组的元素是乱序的不好求。因此先对数组排序。使用了STL库的sort函数&#xff0c;时间复杂度O(nlogn)不符合题目要求&#xff0c;空间复杂度O(1)。…

大陆ARS548使用记录

一、Windows连接上位机 雷达是在深圳路达买的&#xff0c;商家给的资料中首先让配置网口&#xff0c;但我在使用过程中一直出现无法连接上位机的情况。接下来说说我的见解和理解。 1.1遇到的问题 按要求配置好端口后上位机无连接不到雷达&#xff0c;但wireshark可以正常抓到数…

ESP32-C3模组上跑通MQTT(6)—— tcp例程(1)

接前一篇文章:ESP32-C3模组上跑通MQTT(5) 《ESP32-C3 物联网工程开发实战》 一分钟了解MQTT协议 ESP32 MQTT API指南-CSDN博客 ESP-IDF MQTT 示例入门_mqtt outbox-CSDN博客 ESP32用自签CA进行MQTT的TLS双向认证通信_esp32 mqtt ssl-CSDN博客 特此致谢! 本回开始正式讲…

上海站圆满结束!MongoDB Developer Day深圳站,周六见!

在过去两个周六的北京和上海 我们见证了两站热情高涨的 MongoDB Developer Day&#xff01; 近200位参会开发者相聚专业盛会 经过全天的动手实操和主题研讨会 MongoDB技能已是Next Level&#xff01; 最后一站Developer Day即将启程 期待本周六与各位在深圳相见&#xff0…

线程池666666

1. 作用 线程池内部维护了多个工作线程&#xff0c;每个工作线程都会去任务队列中拿取任务并执行&#xff0c;当执行完一个任务后不是马上销毁&#xff0c;而是继续保留执行其它任务。显然&#xff0c;线程池提高了多线程的复用率&#xff0c;减少了创建和销毁线程的时间。 2…

创建kset

1、kset介绍 2、相关结构体和api介绍 2.1 struct kset 2.2 kset_create_and_add kset_create_and_addkset_createkset_registerkobject_add_internalkobject_add_internal2.3 kset_unregister kset_unregisterkobject_delkobject_put3、实验操作 #include<linux/module.…

代码随想录第42天|动态规划

198.打家劫舍 参考 dp[j] 表示偷盗的总金额, j 表示前 j 间房(包括j)的总偷盗金额初始化: dp[0] 一定要偷, dp[1] 则取房间0,1的最大值遍历顺序: 从小到大 class Solution { public:int rob(vector<int>& nums) {if (nums.size() < 2) {return nums[0];}vector&…

[译]Reactjs性能篇

英文有限&#xff0c;技术一般&#xff0c;海涵海涵&#xff0c;由于不是翻译出身&#xff0c;所以存在大量的瞎胡乱翻译的情况&#xff0c;信不过我的&#xff0c;请看原文&#xff5e;&#xff5e; 原文地址&#xff1a;https://facebook.github.io/react/docs/advanced-per…

Java环境变量的设置

JAVA环境变量的设置 1.设置环境变量的作用2.如何设置环境变量2.1 找到系统的环境变量2.2 设置环境变量 1.设置环境变量的作用 说明&#xff1a;在Java中设置环境变量主要是为了能够让Java运行时能够找到Java开发工具包&#xff08;JDK&#xff09;的安装位置以及相关的库文件。…

Zabbix 配置端口监控

Zabbix 端口监控简介 在Zabbix中配置端口监控&#xff0c;可以帮助你实时监控服务器或网络设备上的特定端口是否开放和可访问。Zabbix提供了多种方式来监控端口&#xff0c;主要包括简单的端口可用性检查和更复杂的服务监控。 在Zabbix中进行端口监控时&#xff0c;不一定需要…

Ubuntu 安装Nginx服务

转自&#xff1a;https://blog.csdn.net/yegu001/article/details/135411588 Package: nginx Architecture: amd64 Version: 1.18.0-6ubuntu14.4 Priority: optional Section: web Origin: Ubuntu Maintainer: Ubuntu Developers <ubuntu-devel-discusslists.ubuntu.com>…

可充电纽扣电池ML2032充电电路设计

如图&#xff0c;可充电纽扣电池ML2032充电电路设计。 图中二极管是为了防止电流倒灌&#xff0c; 电阻分压出3.66v&#xff0c;再减掉二极管压降&#xff08;约0.4v)得3.26V&#xff0c;加在电池正负极充电。 随着电池电量的积累&#xff0c;充电电流逐步减小&#xff0c;极限…

魔行观察-AI数据分析-蜜雪冰城

摘要 本报告旨在评估蜜雪冰城品牌作为投资对象的潜力和价值&#xff0c;基于其经营模式、门店分布、人均消费、覆盖省份等关键指标进行分析。 数据数据源&#xff1a;魔行观察&#xff1a;http://www.wmomo.com/#/brand/brandDetails?code10013603 品牌概览 蜜雪冰城是中国…

[Information Sciences 2023]用于假新闻检测的相似性感知多模态提示学习

推荐的一个视频&#xff1a;p-tuning P-tunning直接使用连续空间搜索 做法就是直接将在自然语言中存在的词直接替换成可以直接训练的输入向量。本身的Pretrained LLMs 可以Fine-Tuning也可以不做。 这篇论文也解释了为什么很少在其他领域结合知识图谱的原因&#xff1a;就是因…