Java设计模式之命令模式----解耦请求发出者和请求实现者

一.场景

在这里插入图片描述
在餐厅里,我们要吃饭,就需要对餐厅发出请求,此时,我们是请求发出者。餐厅的厨师则是请求实现者,如果我们直接和厨师交流沟通说自己想吃什么,这时,我们和厨师就是一种强耦合关系,当顾客越来越多,厨师也各司其职的时候,就不好运作了。


解决:通过点餐的菜单来对我们进行解藕,我们把想吃的菜在菜单上勾选,交给服务员,服务员交给厨师,实际上是服务员告诉厨师,调用他的烹饪方法,最后把做好的菜也就是结果返回给我们,这时我们之间是解藕的关系,服务员不会关心我们在菜单上写了什么,厨师也不用和顾客交流。


二.命令模式介绍

定义

命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

使用场景

在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。当我们需要对请求发出者和请求实现者进行解藕时,使用命令模式。


三.类图结构和实现

1.类图

在这里插入图片描述

2.解释
  1. 命令(Command):为所有命令声明了一个接口。调用命令对象的 execute()方法,就可以让接收者进行相关的操作。
  2. 具体命令(ConcreteCommand):实现命令接口,定义了动作和接收者之间的绑定关系。调用者只要调用 execute() 就可以发出请求,然后由 ConcreteCommand 调用接收者的一个或多个动作。
  3. 请求者(Invoker):持有一个命令对象,有一个行动方法,在某个时间点调用命令对象的 execute() 方法,将请求付诸实行
  4. 接收者(Receiver):接收者知道如何进行必要的动作,实现这个请求。任何类都可以当接收者
  5. 客户端(Client):创建一个具体命令(ConcreteCommand)对象并确定其接收者,包括把其他角色串连在一起。

3.和例子对应
  • 服务员 对应Command 它可以调用命令对象的execute()方法
  • 厨师 execute() 负责做菜
  • 菜单 Invoker 请求者 持有命令对象
  • 顾客 Receiver 接受者 就是最后做菜给的人
  • Client 对应谁???

Client是创建命令对象,并确定接受者的角色,在点餐环节,Client其实可以看作是餐厅的接客流程,它需要创建命令对象,将命令对象存储在Invoker中。


四.代码例子:

注意,这个例子选自《Head First 设计模式》一书,并非本人原创。遥控器控制开关灯的例子

1.定义Command

Command很简单,就是一个接口

public interface Command {
    /**
     * 执行命令
     */
    void execute();
}
2.定义接受者,相当于点餐的顾客

这个类负责显示结果给我们看

public class Light {

    public void on() {
        System.out.println("灯亮了...");
    }
}
3.实现一个打开电灯的命令

这个类实现了Command接口,属于ConcreteCommand

public class LightOnCommand implements Command {

    private Light light;

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

    @Override
    public void execute() {
        light.on();
    }
}
4.构建请求者 遥控器

请求者持有一个命令对象,有一个行动方法

public class RemoteInvoker {

	private Command undoCommand;

    /**
     * 开关命令数组,模拟有很多对开关数组
     */
    private Command[] onCommands;
   
    public RemoteInvoker(int length) {
        // 有几组开关,就设置多少数组
        onCommands = new Command[length];
        // 把每个命令初始化成空命令,避免空指针异常
        Command noCommand = new NoCommand();
        undoCommand = noCommand;
        for (int i = 0; i < length; i++) {
            onCommands[i] = noCommand;
        }
    }

    /**
     * @Description 设置命令对象
     * @param slot 遥控器的位置
     * @param onCommand 开的命令
     * @return void
     */
    public void setCommond(int slot, Command onCommand, Command offCommand) {
        onCommands[slot] = onCommand;
    }


    public void onButton(int slot) {
        onCommands[slot].execute();
    }
}
5.定义Client把他们串起来
public class RemoteClient {

    public static void main(String[] args) {
        // 1、创建接收者
        Light light = new Light();
        // 2、创建命令对象
        LightOnCommand lightOnCommand = new LightOnCommand(light);
        // 3、创建一组开关并用命令对象装载它
        RemoteInvoker invoker = new RemoteInvoker(1);
        invoker.setCommond(0, lightOnCommand);
        // 4、测试
        invoker.onButton(0);
    }
}

5.优点和缺点

优点:

  • 降低了系统耦合度。
  • 新的命令可以很容易添加到系统中去。

缺点:

  • 使用命令模式可能会导致某些系统有过多的具体命令类。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
内容简介: 设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。 本课程内容定位学习设计原则,学习设计模式的基础。在实际开发过程中,并不是一定要求所有代码都遵循设计原则,我们要考虑人力、时间、成本、质量,不是刻意追求完美,要在适当的场景遵循设计原则,体现的是一种平衡取舍,帮助我们设计出更加优雅的代码结构。本章将详细介绍开闭原则(OCP)、依赖倒置原则(DIP)、单一职责原则(SRP)、接口隔离原则(ISP)、迪米特法则(LoD)、里氏替换原则(LSP)、合成复用原则(CARP)的具体内容。 为什么需要学习这门课程? 你在日常的开发中,会不会也遇到过同样的问题。系统出现问题,不知道问题究竟出在什么位置;当遇到产品需求,总是对代码缝缝补补,不能很快的去解决。而且平时工作中,总喜欢把代码堆在一起,出现问题时,不知道如何下手,工作效率很低,而且自己的能力也得不到提升。而这些都源于一个问题,那就是软件设计没做好。这门课能帮助你很好的认识设计模式,让你的能力得到提升。课程大纲: 为了让大家快速系统了解设计模式知识全貌,我为您总结了思维导图,帮您梳理学习重点,建议收藏!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值