首页 > 其他分享 >软件设计模式系列之十六——命令模式

软件设计模式系列之十六——命令模式

时间:2023-09-27 09:12:46浏览次数:44  
标签:请求 软件设计 light 十六 接收者 模式 命令 对象

1 模式的定义

命令模式(Command Pattern)是一种行为型设计模式,旨在将请求发送者和接收者解耦,将一个请求封装为一个对象,从而允许您参数化客户端对象以进行不同的请求、排队请求或记录请求,并支持可撤销操作。

命令模式的核心思想是将一个请求包装成一个对象,包括请求的参数和接收者对象,然后客户端只需要调用该对象的方法来执行请求,而不需要关心请求的具体细节。这种方式使得请求的发送者和接收者之间的关系变得松耦合,同时支持一些附加功能,如命令的撤销和重做。

2 举例说明

为了更好地理解命令模式,让我们考虑一个实际的例子:遥控器控制家电。假设您有一个遥控器,可以控制不同种类的家电设备,如电视、音响和灯。每个按钮都代表一个命令,例如打开电视、关闭音响、调暗灯光等。命令模式可以用于实现这种遥控器系统。

在这个例子中,每个命令(如打开电视)都被封装成一个命令对象,包括具体的操作(执行命令)和接收者对象(执行命令的设备)。遥控器上的按钮只需要关联一个命令对象,并在按下按钮时执行该命令。这种方式使得遥控器可以轻松控制不同种类的家电设备,而不需要关心它们的具体实现。

3 结构

命令模式的结构包括以下几个关键部分:

Command(命令):定义一个执行操作的接口,通常包括一个 execute 方法,负责执行具体的命令。

ConcreteCommand(具体命令):实现命令接口,将一个接收者对象绑定到一个操作。它负责调用接收者的方法来执行命令。

Receiver(接收者):负责执行与请求相关的具体操作,是命令真正的执行者。

Invoker(调用者):负责将命令对象传递给接收者执行命令,它不需要知道命令的具体细节,只需调用命令的 execute 方法即可。

Client(客户端):创建具体命令对象,并将命令对象与接收者对象关联,然后将命令对象传递给调用者来执行。

4 实现步骤

实现命令模式时,通常遵循以下步骤:

定义命令接口(Command),其中包括一个 execute 方法用于执行命令。

创建具体命令类(ConcreteCommand),实现命令接口,并在构造函数中绑定一个接收者对象。

定义接收者类(Receiver),负责执行具体的操作。

创建调用者类(Invoker),负责接收命令对象并执行命令。

在客户端中创建命令对象和接收者对象,并将它们关联。然后将命令对象传递给调用者,由调用者执行命令。

5 代码实现

现在,让我们通过 Java 代码来实现上述遥控器控制家电的命令模式。

// 1. 定义命令接口
interface Command {
    void execute();
}

// 2. 创建具体命令类
class LightOnCommand implements Command {
    private Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.turnOn();
    }
}

class LightOffCommand implements Command {
    private Light light;

    public LightOffCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.turnOff();
    }
}

// 3. 定义接收者类
class Light {
    public void turnOn() {
        System.out.println("Light is on");
    }

    public void turnOff() {
        System.out.println("Light is off");
    }
}

// 4. 创建调用者类
class RemoteControl {
    private Command command;

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

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

// 5. 客户端代码
public class Client {
    public static void main(String[] args) {
        // 创建接收者对象
        Light light = new Light();

        // 创建具体命令对象并关联接收者
        Command lightOn = new LightOnCommand(light);
        Command lightOff = new LightOffCommand(light);

        // 创建调用者
        RemoteControl remote = new RemoteControl();

        // 设置命令并执行
        remote.setCommand(lightOn);
        remote.pressButton();

        remote.setCommand(lightOff);
        remote.pressButton();
    }
}

6 典型应用场景

命令模式在实际应用中有多种典型场景,包括但不限于:

遥控器控制:如上面的示例所示,可以用命令模式实现遥控器来控制不同的家电设备,如电视、音响和灯。

文本编辑器操作:文本编辑器中的撤销、重做、剪切、复制、粘贴等操作可以使用命令模式来实现。

菜单系统:图形用户界面(GUI)应用中的菜单项和按钮操作可以通过命令模式来处理。

游戏中的动作:在游戏中,角色的动作和命令(如攻击、防御、跳跃等)可以使用命令模式来处理。

多级撤销操作:命令模式支持撤销和重做操作,因此在需要多级撤销的应用中很有用,如图像编辑器或CAD软件。

日程安排应用:在日程安排应用中,可以使用命令模式来处理添加、编辑、删除事件等操作。

7 优缺点

优点:

解耦发送者和接收者:命令模式将请求的发送者和接收者解耦,发送者不需要知道接收者的具体实现,从而降低了系统的耦合度。

支持撤销和重做:命令模式可以轻松支持命令的撤销和重做,因为每个命令对象都包含了执行和撤销操作的逻辑。

支持扩展:可以轻松添加新的命令和接收者,而无需修改现有的客户端代码。

支持排队请求:命令模式允许将请求排队,以便按照先后顺序执行,或者实现任务调度。

缺点:

可能导致命令类膨胀:如果有大量的命令操作,可能会导致命令类的膨胀,增加维护的复杂性。

不适用于所有情况:命令模式不适用于所有场景,特别是对于简单的命令,直接调用方法可能更加简单和高效。

增加代码复杂性:引入命令模式会增加一定的代码复杂性,因为需要创建额外的命令类和接收者类。

8 类似模式

策略模式(Strategy Pattern):策略模式也可以用于封装可互换的行为,但它的主要目的是在运行时选择算法或策略,而不是将请求封装成命令对象。

观察者模式(Observer Pattern):观察者模式用于定义对象之间的一对多依赖关系,当一个对象状态发生变化时,所有依赖于它的对象都会收到通知。与命令模式不同,观察者模式不涉及命令的封装和执行。

中介者模式(Mediator Pattern):中介者模式用于减少对象之间的直接耦合,将对象之间的通信集中在一个中介者对象中。与命令模式不同,中介者模式通常用于管理对象之间的交互,而不是将请求封装成命令。

9 小结

命令模式是一种有用的设计模式,它允许将请求封装成命令对象,从而解耦请求的发送者和接收者,支持撤销和重做操作,并提供扩展性和灵活性。命令模式在实际应用中有多种典型场景,包括遥控器控制、文本编辑器操作、菜单系统等。虽然命令模式增加了一些复杂性,但它可以提高代码的可维护性和可扩展性,是面向对象设计中的重要模式之一。

标签:请求,软件设计,light,十六,接收者,模式,命令,对象
From: https://www.cnblogs.com/coodream2009/p/17731795.html

相关文章

  • 抽象类、抽象方法、模板方法设计模式的写法
    1、抽象方法:必须用abstarct修饰,只有方法签名,一定不能有方法体抽象类中不一定有抽象方法,有抽象方法的一定是抽象类  2、设计抽象类是为了更好的支持多态------------------------------------------------------------1、模板方法设计模式的写法(使用final修饰)a、定......
  • 设计模式——适配器模式
    一、介绍适配器模式主要是为了解决系统中两个接口实现某个或某类功能但又不兼容的问题,比如国内居民用电电压是220V,手机充电输入电压是5V,在给手机充电时需要将220V电压转换为5V,这个转换装置就可以理解为适配器,软件编程中有时也需要用到这种思想,解决这类问题就需要用到适配器模式。......
  • Redis 主从复制、哨兵模式、群集模式
    Redis主从复制、哨兵模式、群集模式目录1.Redis的2种持久化方式2.Redis优化3.Redis主从复制的原理3.1配置文件3.2Redis主从复制4.Redis哨兵模式4.1哨兵机制4.2哨兵模式的作用4.3哨兵结构4.4哨兵模式配置1.Redis的2种持久化方式RDB持久化定时把red......
  • 向着趋势奔跑:银行客户中心转型,重构商业模式是关键
    随着金融市场化改革的推进国内银行同业间的竞争日趋激烈各商业银行在全新的监管要求和市场环境下纷纷开始推行“以客户为中心”的经营新模式迅速提升核心竞争力然而!!!奇怪的事情发生了......
  • 向着趋势奔跑:银行客户中心转型,重构商业模式是关键
    随着金融市场化改革的推进国内银行同业间的竞争日趋激烈各商业银行在全新的监管要求和市场环境下纷纷开始推行“以客户为中心”的经营新模式迅速提升核心竞争力  然而!!!奇怪的事情发生了......
  • c#中适配器模式详解
    基础介绍:  想象这样一个场景,原项目中接口返回的数据是XML格式的数据,但现在来了一个新客户,它期望接口返回的数据类型为json格式的。  想要实现要么就是改原有接口,但这样就违反了开闭原则,容易出现未知bug,影响到老客户的正常使用。  而如果写一个适配器类也就是转换类(第三方......
  • 自动化模式下,企业全面预算管理的提升
    近年来,经济世界不确定事件的频频发生,让企业开始关注自身的关键财务弱点。企业在财务能力敏捷性提升的方面仍存在一定的差距,而在数字化转型过程中进行的投资不够,将难以推动企业冲出重围,提高前瞻性和自身预测能力。这预示着数字化转型的紧迫性,而部分企业在转型和改革过程中,在不确定的......
  • MySQL正则表达式:模式匹配、中文匹配、替换、提取字符串
    在MySQL中,使用REGEXP或RLIKE操作符进行正则表达式匹配,而使用NOTREGEXP或NOTRLIKE操作符进行不匹配。一些常用的MySQL正则表达式语法:匹配字符:.:匹配任意字符(除了换行符)。[]:匹配方括号中的任意字符。[^]:匹配不在方括号中的任意字符。匹配重复:*:匹配零个或多个前面的字符。+:匹配一个......
  • 第十六篇 - URL链接中包含中文则下载失败
    问题简介:当文件在服务器上,从客户端下载方式一般是:http://ip:port/files/文件名。举个例子:当访问http://11.123.123.12:8080/files/test.xlsx,可以成功下载。当访问http://11.123.123.12:8080/files/test_测试.xlsx,则下载失败,报404错误。解决方案:参考链接:https://blog.csdn.ne......
  • golang 多生产者+多消费者模式
    参考https://gist.github.com/vitan/aedb628a40478cf8b6a33dc87a5ff52fhttps://gist.github.com/mochow13/74ee57078d58536929575ab481dd96931packagemainimport( "errors" "fmt" "math" "reflect" "sync")......